From a581ab1991d49939cbf01e59a5a2c4da131ce044 Mon Sep 17 00:00:00 2001 From: walkline Date: Thu, 11 May 2017 15:31:51 +0300 Subject: [PATCH 001/361] Handle storeImageDataToDisk error. --- SDWebImage/SDImageCache.h | 38 ++++++++++++++++-- SDWebImage/SDImageCache.m | 39 +++++++++++++------ .../project.pbxproj | 6 +++ Tests/Tests/MockFileManager.h | 15 +++++++ Tests/Tests/MockFileManager.m | 29 ++++++++++++++ Tests/Tests/SDImageCacheTests.m | 21 ++++++++++ 6 files changed, 133 insertions(+), 15 deletions(-) create mode 100644 Tests/Tests/MockFileManager.h create mode 100644 Tests/Tests/MockFileManager.m diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 70ee6cea..ef111ca4 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -31,6 +31,7 @@ typedef void(^SDWebImageCheckCacheCompletionBlock)(BOOL isInCache); typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize); +typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable error); /** * SDImageCache maintains a memory cache and an optional disk cache. Disk cache write operations are performed @@ -103,7 +104,7 @@ typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger tot */ - (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key - completion:(nullable SDWebImageNoParamsBlock)completionBlock; + completion:(nullable SDWebImageCompletionWithPossibleErrorBlock)completionBlock; /** * Asynchronously store an image into memory and disk cache at the given key. @@ -116,7 +117,7 @@ typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger tot - (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key toDisk:(BOOL)toDisk - completion:(nullable SDWebImageNoParamsBlock)completionBlock; + completion:(nullable SDWebImageCompletionWithPossibleErrorBlock)completionBlock; /** * Asynchronously store an image into memory and disk cache at the given key. @@ -133,7 +134,7 @@ typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger tot imageData:(nullable NSData *)imageData forKey:(nullable NSString *)key toDisk:(BOOL)toDisk - completion:(nullable SDWebImageNoParamsBlock)completionBlock; + completion:(nullable SDWebImageCompletionWithPossibleErrorBlock)completionBlock; /** * Synchronously store image NSData into disk cache at the given key. @@ -143,7 +144,36 @@ typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger tot * @param imageData The image data to store * @param key The unique image cache key, usually it's image absolute URL */ -- (void)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key; +- (void)storeImageDataToDisk:(nullable NSData *)imageData + forKey:(nullable NSString *)key; + +/** + * Synchronously store image NSData into disk cache at the given key. + * + * @warning This method is synchronous, make sure to call it from the ioQueue + * + * @param imageData The image data to store + * @param key The unique image cache key, usually it's image absolute URL + * @param errorPtr NSError pointer. If error occurs then (*errorPtr) != nil. + */ +- (void)storeImageDataToDisk:(nullable NSData *)imageData + forKey:(nullable NSString *)key + error:(NSError * _Nullable * _Nullable)errorPtr; + +/** + * Synchronously store image NSData into disk cache at the given key. + * + * @warning This method is synchronous, make sure to call it from the ioQueue + * + * @param imageData The image data to store + * @param key The unique image cache key, usually it's image absolute URL + * @param fileManager The file manager for storing image. If nil, then will be used local object. + * @param errorPtr NSError pointer. If error occurs then (*errorPtr) != nil. + */ +- (void)storeImageDataToDisk:(nullable NSData *)imageData + forKey:(nullable NSString *)key + fileManager:(nullable NSFileManager *)fileManager + error:(NSError * _Nullable * _Nullable)errorPtr; #pragma mark - Query and Retrieve Ops diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 61a8bfe4..f9e953ce 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -187,14 +187,14 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { - (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key - completion:(nullable SDWebImageNoParamsBlock)completionBlock { + completion:(nullable SDWebImageCompletionWithPossibleErrorBlock)completionBlock { [self storeImage:image imageData:nil forKey:key toDisk:YES completion:completionBlock]; } - (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key toDisk:(BOOL)toDisk - completion:(nullable SDWebImageNoParamsBlock)completionBlock { + completion:(nullable SDWebImageCompletionWithPossibleErrorBlock)completionBlock { [self storeImage:image imageData:nil forKey:key toDisk:toDisk completion:completionBlock]; } @@ -202,10 +202,10 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { imageData:(nullable NSData *)imageData forKey:(nullable NSString *)key toDisk:(BOOL)toDisk - completion:(nullable SDWebImageNoParamsBlock)completionBlock { + completion:(nullable SDWebImageCompletionWithPossibleErrorBlock)completionBlock { if (!image || !key) { if (completionBlock) { - completionBlock(); + completionBlock(nil); } return; } @@ -217,37 +217,52 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (toDisk) { dispatch_async(self.ioQueue, ^{ + NSError * writeError = nil; @autoreleasepool { NSData *data = imageData; if (!data && image) { SDImageFormat imageFormatFromData = [NSData sd_imageFormatForImageData:data]; data = [image sd_imageDataAsFormat:imageFormatFromData]; } - [self storeImageDataToDisk:data forKey:key]; + [self storeImageDataToDisk:data forKey:key error:&writeError]; } if (completionBlock) { dispatch_async(dispatch_get_main_queue(), ^{ - completionBlock(); + completionBlock(writeError); }); } }); } else { if (completionBlock) { - completionBlock(); + completionBlock(nil); } } } -- (void)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key { +- (void)storeImageDataToDisk:(nullable NSData *)imageData + forKey:(nullable NSString *)key { + [self storeImageDataToDisk:imageData forKey:key fileManager:_fileManager error:nil]; +} + +- (void)storeImageDataToDisk:(nullable NSData *)imageData + forKey:(nullable NSString *)key + error:(NSError * _Nullable * _Nullable)errorPtr { + [self storeImageDataToDisk:imageData forKey:key fileManager:_fileManager error:errorPtr]; +} + +- (void)storeImageDataToDisk:(nullable NSData *)imageData + forKey:(nullable NSString *)key + fileManager:(nullable NSFileManager *)fileManager + error:(NSError * _Nullable * _Nullable)errorPtr { if (!imageData || !key) { return; } [self checkIfQueueIsIOQueue]; - if (![_fileManager fileExistsAtPath:_diskCachePath]) { - [_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL]; + if (![fileManager fileExistsAtPath:_diskCachePath]) { + [fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL]; } // get cache Path for image key @@ -255,7 +270,9 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { // transform to NSUrl NSURL *fileURL = [NSURL fileURLWithPath:cachePathForKey]; - [_fileManager createFileAtPath:cachePathForKey contents:imageData attributes:nil]; + if (![fileManager createFileAtPath:cachePathForKey contents:imageData attributes:nil] && errorPtr) { + *errorPtr = [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]; + } // disable iCloud backup if (self.config.shouldDisableiCloud) { diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 1dfc166d..70005861 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */; }; + 37D122881EC48B5E00D98CEB /* MockFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 37D122871EC48B5E00D98CEB /* MockFileManager.m */; }; 433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */; }; 433BBBB71D7EF8200086B6E9 /* TestImage.gif in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB61D7EF8200086B6E9 /* TestImage.gif */; }; 433BBBB91D7EF8260086B6E9 /* TestImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB81D7EF8260086B6E9 /* TestImage.png */; }; @@ -29,6 +30,8 @@ /* Begin PBXFileReference section */ 1DAAA77E3CA7387F702040D9 /* Pods_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderTests.m; sourceTree = ""; }; + 37D122861EC48B5E00D98CEB /* MockFileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockFileManager.h; sourceTree = ""; }; + 37D122871EC48B5E00D98CEB /* MockFileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MockFileManager.m; sourceTree = ""; }; 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDecoderTests.m; sourceTree = ""; }; 433BBBB61D7EF8200086B6E9 /* TestImage.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = TestImage.gif; sourceTree = ""; }; 433BBBB81D7EF8260086B6E9 /* TestImage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TestImage.png; sourceTree = ""; }; @@ -120,6 +123,8 @@ 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */, 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */, 4369C2731D9804B1007E863A /* SDCategoriesTests.m */, + 37D122861EC48B5E00D98CEB /* MockFileManager.h */, + 37D122871EC48B5E00D98CEB /* MockFileManager.m */, ); path = Tests; sourceTree = ""; @@ -252,6 +257,7 @@ buildActionMask = 2147483647; files = ( 1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */, + 37D122881EC48B5E00D98CEB /* MockFileManager.m in Sources */, 4369C2741D9804B1007E863A /* SDCategoriesTests.m in Sources */, 4369C1D11D97F80F007E863A /* SDWebImagePrefetcherTests.m in Sources */, DA248D69195475D800390AB0 /* SDImageCacheTests.m in Sources */, diff --git a/Tests/Tests/MockFileManager.h b/Tests/Tests/MockFileManager.h new file mode 100644 index 00000000..cc1ed2c1 --- /dev/null +++ b/Tests/Tests/MockFileManager.h @@ -0,0 +1,15 @@ +// +// MockFileManager.h +// SDWebImage Tests +// +// Created by Anton Popovichenko on 11.05.17. +// +// + +#import + +@interface MockFileManager : NSFileManager + +- (id)initWithSendError:(int)errorNumber; + +@end diff --git a/Tests/Tests/MockFileManager.m b/Tests/Tests/MockFileManager.m new file mode 100644 index 00000000..38cd194e --- /dev/null +++ b/Tests/Tests/MockFileManager.m @@ -0,0 +1,29 @@ +// +// MockFileManager.m +// SDWebImage Tests +// +// Created by Anton Popovichenko on 11.05.17. +// +// + +#import "MockFileManager.h" + +@implementation MockFileManager { + int _errorNumber; +} + +- (id)initWithSendError:(int)errorNumber { + self = [super init]; + if (self) { + _errorNumber = errorNumber; + } + + return self; +} + +- (BOOL)createFileAtPath:(NSString *)path contents:(NSData *)data attributes:(NSDictionary *)attr { + errno = _errorNumber; + return !_errorNumber; +} + +@end diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index be42cd17..8fc996cb 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -13,6 +13,7 @@ #import #import +#import "MockFileManager.h" NSString *kImageTestKey = @"TestImageKey.jpg"; @@ -215,6 +216,26 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; }]; } +- (void)test41StoreImageDataToDistWithError { + NSData *imageData = [NSData dataWithContentsOfFile:[self testImagePath]]; + NSError * error = nil; + [self.sharedImageCache storeImageDataToDisk:imageData + forKey:kImageTestKey + fileManager:[[MockFileManager alloc] initWithSendError:EACCES] + error:&error]; + XCTAssertEqual(error.code, EACCES); +} + +- (void)test42StoreImageDataToDiskWithoutError { + NSData *imageData = [NSData dataWithContentsOfFile:[self testImagePath]]; + NSError * error = nil; + [self.sharedImageCache storeImageDataToDisk:imageData + forKey:kImageTestKey + fileManager:[[MockFileManager alloc] initWithSendError:0] + error:&error]; + XCTAssertNil(error); +} + #pragma mark Helper methods - (void)clearAllCaches{ From 03b6d1b7f782a59495c3512975782abc3de906de Mon Sep 17 00:00:00 2001 From: walkline Date: Thu, 11 May 2017 16:00:12 +0300 Subject: [PATCH 002/361] Fixing warnings. --- SDWebImage/SDImageCache.h | 4 ++-- SDWebImage/SDImageCache.m | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index ef111ca4..a0d94bd7 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -156,7 +156,7 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er * @param key The unique image cache key, usually it's image absolute URL * @param errorPtr NSError pointer. If error occurs then (*errorPtr) != nil. */ -- (void)storeImageDataToDisk:(nullable NSData *)imageData +- (BOOL)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key error:(NSError * _Nullable * _Nullable)errorPtr; @@ -170,7 +170,7 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er * @param fileManager The file manager for storing image. If nil, then will be used local object. * @param errorPtr NSError pointer. If error occurs then (*errorPtr) != nil. */ -- (void)storeImageDataToDisk:(nullable NSData *)imageData +- (BOOL)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key fileManager:(nullable NSFileManager *)fileManager error:(NSError * _Nullable * _Nullable)errorPtr; diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index f9e953ce..e2aa3fb3 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -245,18 +245,18 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { [self storeImageDataToDisk:imageData forKey:key fileManager:_fileManager error:nil]; } -- (void)storeImageDataToDisk:(nullable NSData *)imageData +- (BOOL)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key error:(NSError * _Nullable * _Nullable)errorPtr { - [self storeImageDataToDisk:imageData forKey:key fileManager:_fileManager error:errorPtr]; + return [self storeImageDataToDisk:imageData forKey:key fileManager:_fileManager error:errorPtr]; } -- (void)storeImageDataToDisk:(nullable NSData *)imageData +- (BOOL)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key fileManager:(nullable NSFileManager *)fileManager error:(NSError * _Nullable * _Nullable)errorPtr { if (!imageData || !key) { - return; + return YES; } [self checkIfQueueIsIOQueue]; @@ -272,12 +272,15 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (![fileManager createFileAtPath:cachePathForKey contents:imageData attributes:nil] && errorPtr) { *errorPtr = [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]; + return NO; } // disable iCloud backup if (self.config.shouldDisableiCloud) { [fileURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil]; } + + return YES; } #pragma mark - Query and Retrieve Ops From b51e0ca6891ac91172f2c15b4940602c658b2920 Mon Sep 17 00:00:00 2001 From: walkline Date: Wed, 11 Oct 2017 21:11:36 +0300 Subject: [PATCH 003/361] Removing not needed functions in SDImageCache. Using DI with initializer. --- SDWebImage/SDImageCache.h | 38 +++++--------- SDWebImage/SDImageCache.m | 49 ++++++++++--------- .../project.pbxproj | 6 +-- Tests/Tests/SDImageCacheTests.m | 26 ++++++---- 4 files changed, 56 insertions(+), 63 deletions(-) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index a0d94bd7..7d7627bd 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -79,7 +79,18 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er * @param directory Directory to cache disk images in */ - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns - diskCacheDirectory:(nonnull NSString *)directory NS_DESIGNATED_INITIALIZER; + diskCacheDirectory:(nonnull NSString *)directory; + +/** + * Init a new cache store with a specific namespace and directory + * + * @param ns The namespace to use for this cache store + * @param directory Directory to cache disk images in + * @param fileManager The file manager for storing image, if nil then will be created new one + */ +- (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns + diskCacheDirectory:(nonnull NSString *)directory + fileManager:(nullable NSFileManager *)fileManager NS_DESIGNATED_INITIALIZER; #pragma mark - Cache paths @@ -136,17 +147,6 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er toDisk:(BOOL)toDisk completion:(nullable SDWebImageCompletionWithPossibleErrorBlock)completionBlock; -/** - * Synchronously store image NSData into disk cache at the given key. - * - * @warning This method is synchronous, make sure to call it from the ioQueue - * - * @param imageData The image data to store - * @param key The unique image cache key, usually it's image absolute URL - */ -- (void)storeImageDataToDisk:(nullable NSData *)imageData - forKey:(nullable NSString *)key; - /** * Synchronously store image NSData into disk cache at the given key. * @@ -160,20 +160,6 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er forKey:(nullable NSString *)key error:(NSError * _Nullable * _Nullable)errorPtr; -/** - * Synchronously store image NSData into disk cache at the given key. - * - * @warning This method is synchronous, make sure to call it from the ioQueue - * - * @param imageData The image data to store - * @param key The unique image cache key, usually it's image absolute URL - * @param fileManager The file manager for storing image. If nil, then will be used local object. - * @param errorPtr NSError pointer. If error occurs then (*errorPtr) != nil. - */ -- (BOOL)storeImageDataToDisk:(nullable NSData *)imageData - forKey:(nullable NSString *)key - fileManager:(nullable NSFileManager *)fileManager - error:(NSError * _Nullable * _Nullable)errorPtr; #pragma mark - Query and Retrieve Ops diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 4d65d4de..015cab4d 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -84,6 +84,12 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns diskCacheDirectory:(nonnull NSString *)directory { + return [self initWithNamespace:ns diskCacheDirectory:directory fileManager: nil]; +} + +- (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns + diskCacheDirectory:(nonnull NSString *)directory + fileManager:(nullable NSFileManager *)fileManager { if ((self = [super init])) { NSString *fullNamespace = [@"com.hackemist.SDWebImageCache." stringByAppendingString:ns]; @@ -95,7 +101,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { // Init the memory cache _memCache = [[AutoPurgeCache alloc] init]; _memCache.name = fullNamespace; - + // Init the disk cache if (directory != nil) { _diskCachePath = [directory stringByAppendingPathComponent:fullNamespace]; @@ -103,33 +109,40 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { NSString *path = [self makeDiskCachePath:ns]; _diskCachePath = path; } - - dispatch_sync(_ioQueue, ^{ - _fileManager = [NSFileManager new]; - }); - + + if (fileManager == nil) { + dispatch_sync(_ioQueue, ^{ + _fileManager = [NSFileManager new]; + }); + } else { + _fileManager = fileManager; + } + + #if SD_UIKIT // Subscribe to app events [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clearMemory) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deleteOldFiles) name:UIApplicationWillTerminateNotification object:nil]; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backgroundDeleteOldFiles) name:UIApplicationDidEnterBackgroundNotification object:nil]; #endif } - + return self; + } + - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; SDDispatchQueueRelease(_ioQueue); @@ -240,29 +253,17 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } } -- (void)storeImageDataToDisk:(nullable NSData *)imageData - forKey:(nullable NSString *)key { - [self storeImageDataToDisk:imageData forKey:key fileManager:_fileManager error:nil]; -} - - (BOOL)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key error:(NSError * _Nullable * _Nullable)errorPtr { - return [self storeImageDataToDisk:imageData forKey:key fileManager:_fileManager error:errorPtr]; -} - -- (BOOL)storeImageDataToDisk:(nullable NSData *)imageData - forKey:(nullable NSString *)key - fileManager:(nullable NSFileManager *)fileManager - error:(NSError * _Nullable * _Nullable)errorPtr { if (!imageData || !key) { return YES; } [self checkIfQueueIsIOQueue]; - if (![fileManager fileExistsAtPath:_diskCachePath]) { - [fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL]; + if (![_fileManager fileExistsAtPath:_diskCachePath]) { + [_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL]; } // get cache Path for image key @@ -270,7 +271,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { // transform to NSUrl NSURL *fileURL = [NSURL fileURLWithPath:cachePathForKey]; - if (![fileManager createFileAtPath:cachePathForKey contents:imageData attributes:nil] && errorPtr) { + if (![_fileManager createFileAtPath:cachePathForKey contents:imageData attributes:nil] && errorPtr) { *errorPtr = [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]; return NO; } diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index fa18fcb9..acf7b0e6 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -8,8 +8,8 @@ /* Begin PBXBuildFile section */ 1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */; }; - 37D122881EC48B5E00D98CEB /* MockFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 37D122871EC48B5E00D98CEB /* MockFileManager.m */; }; 2D7AF0601F329763000083C2 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; }; + 37D122881EC48B5E00D98CEB /* MockFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 37D122871EC48B5E00D98CEB /* MockFileManager.m */; }; 433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */; }; 433BBBB71D7EF8200086B6E9 /* TestImage.gif in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB61D7EF8200086B6E9 /* TestImage.gif */; }; 433BBBB91D7EF8260086B6E9 /* TestImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB81D7EF8260086B6E9 /* TestImage.png */; }; @@ -31,10 +31,10 @@ /* Begin PBXFileReference section */ 1DAAA77E3CA7387F702040D9 /* Pods_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderTests.m; sourceTree = ""; }; - 37D122861EC48B5E00D98CEB /* MockFileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockFileManager.h; sourceTree = ""; }; - 37D122871EC48B5E00D98CEB /* MockFileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MockFileManager.m; sourceTree = ""; }; 2D7AF05E1F329763000083C2 /* SDTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDTestCase.h; sourceTree = ""; }; 2D7AF05F1F329763000083C2 /* SDTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDTestCase.m; sourceTree = ""; }; + 37D122861EC48B5E00D98CEB /* MockFileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockFileManager.h; sourceTree = ""; }; + 37D122871EC48B5E00D98CEB /* MockFileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MockFileManager.m; sourceTree = ""; }; 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDecoderTests.m; sourceTree = ""; }; 433BBBB61D7EF8200086B6E9 /* TestImage.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = TestImage.gif; sourceTree = ""; }; 433BBBB81D7EF8260086B6E9 /* TestImage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TestImage.png; sourceTree = ""; }; diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index 5338f303..7fca4f78 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -193,7 +193,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test40InsertionOfImageData { NSData *imageData = [NSData dataWithContentsOfFile:[self testImagePath]]; - [self.sharedImageCache storeImageDataToDisk:imageData forKey:kImageTestKey]; + [self.sharedImageCache storeImageDataToDisk:imageData forKey:kImageTestKey error:nil]; UIImage *storedImageFromMemory = [self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]; expect(storedImageFromMemory).to.equal(nil); @@ -211,23 +211,29 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; }]; } -- (void)test41StoreImageDataToDistWithError { +- (void)test41StoreImageDataToDiskWithError { NSData *imageData = [NSData dataWithContentsOfFile:[self testImagePath]]; NSError * error = nil; - [self.sharedImageCache storeImageDataToDisk:imageData - forKey:kImageTestKey - fileManager:[[MockFileManager alloc] initWithSendError:EACCES] - error:&error]; + SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"test" + diskCacheDirectory:@"/" + fileManager:[[MockFileManager alloc] initWithSendError:EACCES]]; + [cache storeImageDataToDisk:imageData + forKey:kImageTestKey + error:&error]; + XCTAssertEqual(error.code, EACCES); } - (void)test42StoreImageDataToDiskWithoutError { NSData *imageData = [NSData dataWithContentsOfFile:[self testImagePath]]; NSError * error = nil; - [self.sharedImageCache storeImageDataToDisk:imageData - forKey:kImageTestKey - fileManager:[[MockFileManager alloc] initWithSendError:0] - error:&error]; + SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"test" + diskCacheDirectory:@"/" + fileManager:[[MockFileManager alloc] initWithSendError:0]]; + [cache storeImageDataToDisk:imageData + forKey:kImageTestKey + error:&error]; + XCTAssertNil(error); } From 1644d71e7f4bc478e3c21069c2d52dc207bb9651 Mon Sep 17 00:00:00 2001 From: walkline Date: Tue, 17 Oct 2017 22:49:30 +0300 Subject: [PATCH 004/361] Fixes fail condition in storeImageDataToDisk. Removes extra spaces. --- SDWebImage/SDImageCache.h | 2 +- SDWebImage/SDImageCache.m | 23 ++++++++--------------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 7d7627bd..4b1dbaa5 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -82,7 +82,7 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er diskCacheDirectory:(nonnull NSString *)directory; /** - * Init a new cache store with a specific namespace and directory + * Init a new cache store with a specific namespace, directory and file manager * * @param ns The namespace to use for this cache store * @param directory Directory to cache disk images in diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 015cab4d..b01dd867 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -101,7 +101,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { // Init the memory cache _memCache = [[AutoPurgeCache alloc] init]; _memCache.name = fullNamespace; - + // Init the disk cache if (directory != nil) { _diskCachePath = [directory stringByAppendingPathComponent:fullNamespace]; @@ -110,14 +110,9 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { _diskCachePath = path; } - if (fileManager == nil) { - dispatch_sync(_ioQueue, ^{ - _fileManager = [NSFileManager new]; - }); - } else { - _fileManager = fileManager; - } - + dispatch_sync(_ioQueue, ^{ + _fileManager = fileManager ? fileManager : [NSFileManager new]; + }); #if SD_UIKIT // Subscribe to app events @@ -125,24 +120,22 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { selector:@selector(clearMemory) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deleteOldFiles) name:UIApplicationWillTerminateNotification object:nil]; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backgroundDeleteOldFiles) name:UIApplicationDidEnterBackgroundNotification object:nil]; #endif } - + return self; - } - - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; SDDispatchQueueRelease(_ioQueue); @@ -257,7 +250,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { forKey:(nullable NSString *)key error:(NSError * _Nullable * _Nullable)errorPtr { if (!imageData || !key) { - return YES; + return NO; } [self checkIfQueueIsIOQueue]; From 879ea189a4bfb5aad4354c1a9a98e20a59f5b2fe Mon Sep 17 00:00:00 2001 From: walkline Date: Tue, 17 Oct 2017 22:52:01 +0300 Subject: [PATCH 005/361] =?UTF-8?q?=20My=20IDE=20loves=20extra=20spaces=20?= =?UTF-8?q?=F0=9F=99=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SDWebImage/SDImageCache.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index b01dd867..6c933242 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -109,11 +109,11 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { NSString *path = [self makeDiskCachePath:ns]; _diskCachePath = path; } - + dispatch_sync(_ioQueue, ^{ _fileManager = fileManager ? fileManager : [NSFileManager new]; }); - + #if SD_UIKIT // Subscribe to app events [[NSNotificationCenter defaultCenter] addObserver:self From caafe27937bf81e67b282580c4f57d0d7317e662 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 1 Jan 2018 13:15:51 +0800 Subject: [PATCH 006/361] Upgrade target deployment version to iOS 8.0 / macOS 10.10 --- SDWebImage.podspec | 10 +++++----- SDWebImage.xcodeproj/project.pbxproj | 4 ++-- Tests/SDWebImage Tests.xcodeproj/project.pbxproj | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SDWebImage.podspec b/SDWebImage.podspec index 3433cd6d..d478d200 100644 --- a/SDWebImage.podspec +++ b/SDWebImage.podspec @@ -2,8 +2,8 @@ Pod::Spec.new do |s| s.name = 'SDWebImage' s.version = '4.2.3' - s.osx.deployment_target = '10.8' - s.ios.deployment_target = '7.0' + s.osx.deployment_target = '10.10' + s.ios.deployment_target = '8.0' s.tvos.deployment_target = '9.0' s.watchos.deployment_target = '2.0' @@ -33,8 +33,8 @@ Pod::Spec.new do |s| end s.subspec 'MapKit' do |mk| - mk.osx.deployment_target = '10.8' - mk.ios.deployment_target = '7.0' + mk.osx.deployment_target = '10.10' + mk.ios.deployment_target = '8.0' mk.tvos.deployment_target = '9.0' mk.source_files = 'SDWebImage/MKAnnotationView+WebCache.*' mk.framework = 'MapKit' @@ -42,7 +42,7 @@ Pod::Spec.new do |s| end s.subspec 'GIF' do |gif| - gif.ios.deployment_target = '7.0' + gif.ios.deployment_target = '8.0' gif.source_files = 'SDWebImage/FLAnimatedImage/*.{h,m}' gif.dependency 'SDWebImage/Core' gif.dependency 'FLAnimatedImage', '~> 1.0' diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index fac78404..e9f68f23 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -3694,7 +3694,7 @@ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; INFOPLIST_FILE = WebImage/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.$(PRODUCT_NAME:rfc1034identifier).ios"; PRODUCT_NAME = SDWebImage; @@ -3715,7 +3715,7 @@ ENABLE_STRICT_OBJC_MSGSEND = YES; INFOPLIST_FILE = WebImage/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.$(PRODUCT_NAME:rfc1034identifier).ios"; PRODUCT_NAME = SDWebImage; diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 3bfb4376..3330fb2a 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -234,7 +234,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; 85E5D3885A03BFC23B050908 /* [CP] Copy Pods Resources */ = { From db5307eb9404a3f1f33a9da6591c9e6ff0d24def Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 30 Dec 2017 02:16:52 +0800 Subject: [PATCH 007/361] Change our imageCache `storeImageDataToDisk` to internal use IO-queue. And also change error from POSIX errno to Cocoa file error --- SDWebImage/SDImageCache.h | 6 ++--- SDWebImage/SDImageCache.m | 40 +++++++++++++++++++---------- SDWebImage/SDWebImageImageIOCoder.m | 2 -- Tests/Tests/SDImageCacheTests.m | 15 +++++++---- Tests/Tests/SDMockFileManager.h | 3 ++- Tests/Tests/SDMockFileManager.m | 27 +++++++++---------- 6 files changed, 54 insertions(+), 39 deletions(-) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 4b1dbaa5..1fd3f3c9 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -150,15 +150,13 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er /** * Synchronously store image NSData into disk cache at the given key. * - * @warning This method is synchronous, make sure to call it from the ioQueue - * * @param imageData The image data to store * @param key The unique image cache key, usually it's image absolute URL - * @param errorPtr NSError pointer. If error occurs then (*errorPtr) != nil. + * @param error NSError pointer, for possible file I/O errors, See FoundationErrors.h */ - (BOOL)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key - error:(NSError * _Nullable * _Nullable)errorPtr; + error:(NSError * _Nullable * _Nullable)error; #pragma mark - Query and Retrieve Ops diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 7701a1f5..d8f09885 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -137,14 +137,6 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { [[NSNotificationCenter defaultCenter] removeObserver:self]; } -- (void)checkIfQueueIsIOQueue { - const char *currentQueueLabel = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL); - const char *ioQueueLabel = dispatch_queue_get_label(self.ioQueue); - if (strcmp(currentQueueLabel, ioQueueLabel) != 0) { - NSLog(@"This method should be called from the ioQueue"); - } -} - #pragma mark - Cache paths - (void)addReadOnlyCachePath:(nonnull NSString *)path { @@ -233,7 +225,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } data = [[SDWebImageCodersManager sharedInstance] encodedDataWithImage:image format:format]; } - [self storeImageDataToDisk:data forKey:key error:&writeError]; + [self safeStoreImageDataToDisk:data forKey:key error:&writeError]; } if (completionBlock) { @@ -251,15 +243,34 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { - (BOOL)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key - error:(NSError * _Nullable * _Nullable)errorPtr { + error:(NSError * _Nullable __autoreleasing * _Nullable)error { if (!imageData || !key) { return NO; } + __autoreleasing NSError *fileError; + if (!error) { + error = &fileError; + } - [self checkIfQueueIsIOQueue]; + __block BOOL success = YES; + void(^storeImageDataBlock)(void) = ^{ + success = [self safeStoreImageDataToDisk:imageData forKey:key error:error]; + }; + dispatch_sync(self.ioQueue, storeImageDataBlock); + return success; +} + +- (BOOL)safeStoreImageDataToDisk:(nullable NSData *)imageData + forKey:(nullable NSString *)key + error:(NSError * _Nullable __autoreleasing * _Nonnull)error { + if (!imageData || !key) { + return NO; + } if (![_fileManager fileExistsAtPath:_diskCachePath]) { - [_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL]; + if (![_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:error]) { + return NO; + } } // get cache Path for image key @@ -267,8 +278,9 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { // transform to NSUrl NSURL *fileURL = [NSURL fileURLWithPath:cachePathForKey]; - if (![_fileManager createFileAtPath:cachePathForKey contents:imageData attributes:nil] && errorPtr) { - *errorPtr = [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]; + // NSFileManager's `createFileAtPath:` is used just for old code compatibility and will not trigger any delegate methods, so it's useless for custom NSFileManager at all. + // And also, NSFileManager's `createFileAtPath:` can only grab underlying POSIX errno, but NSData can grab errors defined in NSCocoaErrorDomain, which is better for user to check. + if (![imageData writeToFile:cachePathForKey options:NSDataWritingAtomic error:error]) { return NO; } diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index 25c2d194..f86de89c 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -540,8 +540,6 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over result = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:exifOrientation]; } // else - if it's not set it remains at up CFRelease((CFTypeRef) properties); - } else { - //NSLog(@"NO PROPERTIES, FAIL"); } CFRelease(imageSource); } diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index 6066555e..efec8f06 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -309,23 +309,28 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test41StoreImageDataToDiskWithError { NSData *imageData = [NSData dataWithContentsOfFile:[self testImagePath]]; - NSError * error = nil; + NSError *targetError = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteNoPermissionError userInfo:nil]; + NSError *error = nil; + SDMockFileManager *fileManager = [[SDMockFileManager alloc] init]; + fileManager.mockSelectors = @{NSStringFromSelector(@selector(createDirectoryAtPath:withIntermediateDirectories:attributes:error:)) : targetError}; SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"test" diskCacheDirectory:@"/" - fileManager:[[SDMockFileManager alloc] initWithError:EACCES]]; + fileManager:fileManager]; [cache storeImageDataToDisk:imageData forKey:kImageTestKey error:&error]; - XCTAssertEqual(error.code, EACCES); + XCTAssertEqual(error.code, NSFileWriteNoPermissionError); } - (void)test42StoreImageDataToDiskWithoutError { NSData *imageData = [NSData dataWithContentsOfFile:[self testImagePath]]; - NSError * error = nil; + NSError *error = nil; + SDMockFileManager *fileManager = [[SDMockFileManager alloc] init]; + fileManager.mockSelectors = @{NSStringFromSelector(@selector(createDirectoryAtPath:withIntermediateDirectories:attributes:error:)) : [NSNull null]}; SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"test" diskCacheDirectory:@"/" - fileManager:[[SDMockFileManager alloc] initWithError:0]]; + fileManager:fileManager]; [cache storeImageDataToDisk:imageData forKey:kImageTestKey error:&error]; diff --git a/Tests/Tests/SDMockFileManager.h b/Tests/Tests/SDMockFileManager.h index e5d4edfc..d93d1ac4 100644 --- a/Tests/Tests/SDMockFileManager.h +++ b/Tests/Tests/SDMockFileManager.h @@ -8,8 +8,9 @@ #import +// This is a mock class to provide custom error for methods @interface SDMockFileManager : NSFileManager -- (id)initWithError:(int)errorNumber; +@property (nonatomic, copy, nullable) NSDictionary *mockSelectors; // used to specify mocked selectors which will return NO with specify error instead of normal process. If you specify a NSNull, will use nil instead. @end diff --git a/Tests/Tests/SDMockFileManager.m b/Tests/Tests/SDMockFileManager.m index 60202f4b..472797fb 100644 --- a/Tests/Tests/SDMockFileManager.m +++ b/Tests/Tests/SDMockFileManager.m @@ -10,24 +10,25 @@ @interface SDMockFileManager () -@property (nonatomic, assign) int errorNumber; - @end @implementation SDMockFileManager -- (id)initWithError:(int)errorNumber { - self = [super init]; - if (self) { - _errorNumber = errorNumber; +- (BOOL)createDirectoryAtPath:(NSString *)path withIntermediateDirectories:(BOOL)createIntermediates attributes:(NSDictionary *)attributes error:(NSError * _Nullable __autoreleasing *)error { + NSError *mockError = [self.mockSelectors objectForKey:NSStringFromSelector(_cmd)]; + if ([mockError isEqual:[NSNull null]]) { + if (error) { + *error = nil; + } + return NO; + } else if (mockError) { + if (error) { + *error = mockError; + } + return NO; + } else { + return [super createDirectoryAtPath:path withIntermediateDirectories:createIntermediates attributes:attributes error:error]; } - - return self; -} - -- (BOOL)createFileAtPath:(NSString *)path contents:(NSData *)data attributes:(NSDictionary *)attr { - errno = self.errorNumber; - return (self.errorNumber == 0); } @end From 0d7c93d7b77ef9f2fe0f9eb8e938849c520f1553 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 30 Dec 2017 03:09:55 +0800 Subject: [PATCH 008/361] Add a `diskCacheWritingOptions` to allow user to specify disk data writing options --- SDWebImage/SDImageCache.m | 2 +- SDWebImage/SDImageCacheConfig.h | 8 +++++++- SDWebImage/SDImageCacheConfig.m | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index d8f09885..88b37c17 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -280,7 +280,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { // NSFileManager's `createFileAtPath:` is used just for old code compatibility and will not trigger any delegate methods, so it's useless for custom NSFileManager at all. // And also, NSFileManager's `createFileAtPath:` can only grab underlying POSIX errno, but NSData can grab errors defined in NSCocoaErrorDomain, which is better for user to check. - if (![imageData writeToFile:cachePathForKey options:NSDataWritingAtomic error:error]) { + if (![imageData writeToFile:cachePathForKey options:self.config.diskCacheWritingOptions error:error]) { return NO; } diff --git a/SDWebImage/SDImageCacheConfig.h b/SDWebImage/SDImageCacheConfig.h index 20f2d108..d3cb5421 100644 --- a/SDWebImage/SDImageCacheConfig.h +++ b/SDWebImage/SDImageCacheConfig.h @@ -29,10 +29,16 @@ /** * The reading options while reading cache from disk. - * Defaults to 0. You can set this to mapped file to improve performance. + * Defaults to 0. You can set this to `NSDataReadingMappedIfSafe` to improve performance. */ @property (assign, nonatomic) NSDataReadingOptions diskCacheReadingOptions; +/** + * The writing options while writing cache to disk. + * Defaults to `NSDataWritingAtomic`. You can set this to `NSDataWritingWithoutOverwriting` to prevent overwriting an existing file. + */ +@property (assign, nonatomic) NSDataWritingOptions diskCacheWritingOptions; + /** * The maximum length of time to keep an image in the cache, in seconds. */ diff --git a/SDWebImage/SDImageCacheConfig.m b/SDWebImage/SDImageCacheConfig.m index 7a5af6cb..923506d0 100644 --- a/SDWebImage/SDImageCacheConfig.m +++ b/SDWebImage/SDImageCacheConfig.m @@ -18,6 +18,7 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week _shouldDisableiCloud = YES; _shouldCacheImagesInMemory = YES; _diskCacheReadingOptions = 0; + _diskCacheWritingOptions = NSDataWritingAtomic; _maxCacheAge = kDefaultCacheMaxCacheAge; _maxCacheSize = 0; } From 803210912d71e8b366154b0742382712007842b0 Mon Sep 17 00:00:00 2001 From: Ming Zhang Date: Wed, 10 Jan 2018 19:39:48 +0800 Subject: [PATCH 009/361] fix 'nullable' to 'nonull' --- SDWebImage/SDWebImageManager.h | 2 +- SDWebImage/SDWebImageManager.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index ba8b7555..b9517473 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -222,7 +222,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; - (nullable id )loadImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDInternalCompletionBlock)completedBlock; + completed:(nonnull SDInternalCompletionBlock)completedBlock; /** * Saves image to cache for given URL diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index e1e7e575..11e92734 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -109,7 +109,7 @@ - (id )loadImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDInternalCompletionBlock)completedBlock { + completed:(nonnull SDInternalCompletionBlock)completedBlock { // Invoking this method without a completedBlock is pointless NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead"); From 030a3378da86d49ffdfd8315ea7b5951bc8a8374 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 5 Jan 2018 12:59:21 +0800 Subject: [PATCH 010/361] Move that `maxMemoryCost` and `maxMemoryCountLimit` to config property. Add sync version API `diskImageDataExistsWithKey` --- SDWebImage/SDImageCache.h | 45 ++++++++++++------------- SDWebImage/SDImageCache.m | 59 ++++++++++++++++++++------------- SDWebImage/SDImageCacheConfig.h | 22 ++++++++++-- 3 files changed, 76 insertions(+), 50 deletions(-) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 91104485..72384874 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -57,16 +57,6 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er */ @property (nonatomic, nonnull, readonly) SDImageCacheConfig *config; -/** - * The maximum "total cost" of the in-memory image cache. The cost function is the number of pixels held in memory. - */ -@property (assign, nonatomic) NSUInteger maxMemoryCost; - -/** - * The maximum number of objects the cache should hold. - */ -@property (assign, nonatomic) NSUInteger maxMemoryCountLimit; - #pragma mark - Singleton and initialization /** @@ -133,7 +123,7 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er * * @param image The image to store * @param key The unique image cache key, usually it's image absolute URL - * @param toDisk Store the image to disk cache if YES + * @param toDisk Store the image to disk cache if YES. If NO, the completion block is called synchronously * @param completionBlock A block executed after the operation is finished */ - (void)storeImage:(nullable UIImage *)image @@ -149,7 +139,7 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er * instead of converting the given image object into a storable/compressed image format in order * to save quality and CPU * @param key The unique image cache key, usually it's image absolute URL - * @param toDisk Store the image to disk cache if YES + * @param toDisk Store the image to disk cache if YES. If NO, the completion block is called synchronously * @param completionBlock A block executed after the operation is finished */ - (void)storeImage:(nullable UIImage *)image @@ -173,7 +163,7 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er #pragma mark - Query and Retrieve Ops /** - * Async check if image exists in disk cache already (does not load the image) + * Asynchronously check if image exists in disk cache already (does not load the image) * * @param key the key describing the url * @param completionBlock the block to be executed when the check is done. @@ -182,7 +172,14 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er - (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock; /** - * Operation that queries the cache asynchronously and call the completion when done. + * Synchronously check if image data exists in disk cache already (does not load the image) + * + * @param key the key describing the url + */ +- (BOOL)diskImageDataExistsWithKey:(nullable NSString *)key; + +/** + * Asynchronously queries the cache with operation and call the completion when done. * * @param key The unique key used to store the wanted image * @param doneBlock The completion block. Will not get called if the operation is cancelled @@ -192,7 +189,7 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er - (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock; /** - * Operation that queries the cache asynchronously and call the completion when done. + * Asynchronously queries the cache with operation and call the completion when done. * * @param key The unique key used to store the wanted image * @param options A mask to specify options to use for this cache query @@ -203,21 +200,21 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er - (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock; /** - * Query the memory cache synchronously. + * Synchronously query the memory cache. * * @param key The unique key used to store the image */ - (nullable UIImage *)imageFromMemoryCacheForKey:(nullable NSString *)key; /** - * Query the disk cache synchronously. + * Synchronously query the disk cache. * * @param key The unique key used to store the image */ - (nullable UIImage *)imageFromDiskCacheForKey:(nullable NSString *)key; /** - * Query the cache (memory and or disk) synchronously after checking the memory cache. + * Synchronously query the cache (memory and or disk) after checking the memory cache. * * @param key The unique key used to store the image */ @@ -226,7 +223,7 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er #pragma mark - Remove Ops /** - * Remove the image from memory and disk cache asynchronously + * Asynchronously remove the image from memory and disk cache * * @param key The unique image cache key * @param completion A block that should be executed after the image has been removed (optional) @@ -234,10 +231,10 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er - (void)removeImageForKey:(nullable NSString *)key withCompletion:(nullable SDWebImageNoParamsBlock)completion; /** - * Remove the image from memory and optionally disk cache asynchronously + * Asynchronously remove the image from memory and optionally disk cache * * @param key The unique image cache key - * @param fromDisk Also remove cache entry from disk if YES + * @param fromDisk Also remove cache entry from disk if YES. If NO, the completion block is called synchronously * @param completion A block that should be executed after the image has been removed (optional) */ - (void)removeImageForKey:(nullable NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(nullable SDWebImageNoParamsBlock)completion; @@ -245,18 +242,18 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er #pragma mark - Cache clean Ops /** - * Clear all memory cached images + * Synchronously Clear all memory cached images */ - (void)clearMemory; /** - * Async clear all disk cached images. Non-blocking method - returns immediately. + * Asynchronously clear all disk cached images. Non-blocking method - returns immediately. * @param completion A block that should be executed after cache expiration completes (optional) */ - (void)clearDiskOnCompletion:(nullable SDWebImageNoParamsBlock)completion; /** - * Async remove all expired cached image from disk. Non-blocking method - returns immediately. + * Asynchronously remove all expired cached image from disk. Non-blocking method - returns immediately. * @param completionBlock A block that should be executed after cache expiration completes (optional) */ - (void)deleteOldFilesWithCompletionBlock:(nullable SDWebImageNoParamsBlock)completionBlock; diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 33731569..bca1c3da 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -11,6 +11,8 @@ #import "NSImage+WebCache.h" #import "SDWebImageCodersManager.h" +static void * SDImageCacheContext = &SDImageCacheContext; + FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { #if SD_MAC return image.size.height * image.size.width; @@ -69,6 +71,9 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { _ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL); _config = [[SDImageCacheConfig alloc] init]; + // KVO config property which need to be passed + [_config addObserver:self forKeyPath:NSStringFromSelector(@selector(maxMemoryCost)) options:0 context:SDImageCacheContext]; + [_config addObserver:self forKeyPath:NSStringFromSelector(@selector(maxMemoryCount)) options:0 context:SDImageCacheContext]; // Init the memory cache _memCache = [[NSCache alloc] init]; @@ -109,6 +114,8 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } - (void)dealloc { + [_config removeObserver:self forKeyPath:NSStringFromSelector(@selector(maxMemoryCost)) context:SDImageCacheContext]; + [_config removeObserver:self forKeyPath:NSStringFromSelector(@selector(maxMemoryCount)) context:SDImageCacheContext]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } @@ -255,12 +262,13 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { // NSFileManager's `createFileAtPath:` is used just for old code compatibility and will not trigger any delegate methods, so it's useless for custom NSFileManager at all. // And also, NSFileManager's `createFileAtPath:` can only grab underlying POSIX errno, but NSData can grab errors defined in NSCocoaErrorDomain, which is better for user to check. - if (![imageData writeToFile:cachePathForKey options:self.config.diskCacheWritingOptions error:error]) { + if (![imageData writeToURL:fileURL options:self.config.diskCacheWritingOptions error:error]) { return NO; } // disable iCloud backup if (self.config.shouldDisableiCloud) { + // ignore iCloud backup resource value error [fileURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil]; } @@ -271,13 +279,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { - (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock { dispatch_async(_ioQueue, ^{ - BOOL exists = [_fileManager fileExistsAtPath:[self defaultCachePathForKey:key]]; - - // fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name - // checking the key with and without the extension - if (!exists) { - exists = [_fileManager fileExistsAtPath:[self defaultCachePathForKey:key].stringByDeletingPathExtension]; - } + BOOL exists = [self diskImageDataExistsWithKey:key]; if (completionBlock) { dispatch_async(dispatch_get_main_queue(), ^{ @@ -287,6 +289,21 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { }); } +- (BOOL)diskImageDataExistsWithKey:(nullable NSString *)key { + if (!key) { + return NO; + } + BOOL exists = [_fileManager fileExistsAtPath:[self defaultCachePathForKey:key]]; + + // fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name + // checking the key with and without the extension + if (!exists) { + exists = [_fileManager fileExistsAtPath:[self defaultCachePathForKey:key].stringByDeletingPathExtension]; + } + + return exists; +} + - (nullable UIImage *)imageFromMemoryCacheForKey:(nullable NSString *)key { return [self.memCache objectForKey:key]; } @@ -460,22 +477,18 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } -# pragma mark - Mem Cache settings +#pragma mark - KVO -- (void)setMaxMemoryCost:(NSUInteger)maxMemoryCost { - self.memCache.totalCostLimit = maxMemoryCost; -} - -- (NSUInteger)maxMemoryCost { - return self.memCache.totalCostLimit; -} - -- (NSUInteger)maxMemoryCountLimit { - return self.memCache.countLimit; -} - -- (void)setMaxMemoryCountLimit:(NSUInteger)maxCountLimit { - self.memCache.countLimit = maxCountLimit; +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if (context == SDImageCacheContext) { + if ([keyPath isEqualToString:NSStringFromSelector(@selector(maxMemoryCost))]) { + self.memCache.totalCostLimit = self.config.maxMemoryCost; + } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(maxMemoryCount))]) { + self.memCache.countLimit = self.config.maxMemoryCount; + } + } else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; + } } #pragma mark - Cache clean Ops diff --git a/SDWebImage/SDImageCacheConfig.h b/SDWebImage/SDImageCacheConfig.h index d3cb5421..570072ae 100644 --- a/SDWebImage/SDImageCacheConfig.h +++ b/SDWebImage/SDImageCacheConfig.h @@ -12,18 +12,20 @@ @interface SDImageCacheConfig : NSObject /** - * Decompressing images that are downloaded and cached can improve performance but can consume lot of memory. + * Decompressing images means pre-decoding the image that are downloaded and cached on background queue. This can avoid image view decode it on main queue when rendering. This can improve performance but can consume more memory. * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. */ @property (assign, nonatomic) BOOL shouldDecompressImages; /** - * disable iCloud backup [defaults to YES] + * Whether or not to disable iCloud backup + * Defaults to YES. */ @property (assign, nonatomic) BOOL shouldDisableiCloud; /** - * use memory cache [defaults to YES] + * Whether or not to use memory cache + * Defaults to YES. */ @property (assign, nonatomic) BOOL shouldCacheImagesInMemory; @@ -41,12 +43,26 @@ /** * The maximum length of time to keep an image in the cache, in seconds. + * Defaults to 1 weak. */ @property (assign, nonatomic) NSInteger maxCacheAge; /** * The maximum size of the cache, in bytes. + * Defaults to 0. Which means there is no cache size limit. */ @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. + * 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. + * Defaults to 0. Which means there is no memory count limit. + */ +@property (assign, nonatomic) NSUInteger maxMemoryCount; + @end From 9c124435b69c0b384aa1ad6f780d32cb7173196f Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 4 Jan 2018 20:59:21 +0800 Subject: [PATCH 011/361] Move the imageLoopCount and isAnimated into UIImage+WebCache file, removed the outdated methods --- SDWebImage.xcodeproj/project.pbxproj | 28 +++++++++++ SDWebImage/NSImage+WebCache.h | 9 ++-- SDWebImage/NSImage+WebCache.m | 15 +----- SDWebImage/SDWebImageCompat.m | 2 +- SDWebImage/SDWebImageFrame.h | 2 +- SDWebImage/SDWebImageGIFCoder.m | 2 +- SDWebImage/SDWebImageWebPCoder.m | 2 +- SDWebImage/UIImage+GIF.h | 7 +-- SDWebImage/UIImage+GIF.m | 5 -- SDWebImage/UIImage+MultiFormat.h | 12 ----- SDWebImage/UIImage+MultiFormat.m | 42 ---------------- SDWebImage/UIImage+WebCache.h | 32 +++++++++++++ SDWebImage/UIImage+WebCache.m | 71 ++++++++++++++++++++++++++++ SDWebImage/UIImage+WebP.h | 11 ----- SDWebImage/UIImage+WebP.m | 5 -- WebImage/SDWebImage.h | 1 + 16 files changed, 141 insertions(+), 105 deletions(-) create mode 100644 SDWebImage/UIImage+WebCache.h create mode 100644 SDWebImage/UIImage+WebCache.m diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index e9f68f23..4618c0bb 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -319,6 +319,18 @@ 3290FA0D1FA478AF0047D20C /* SDWebImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */; }; 3290FA0E1FA478AF0047D20C /* SDWebImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */; }; 3290FA0F1FA478AF0047D20C /* SDWebImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */; }; + 329A18591FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 329A185A1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 329A185B1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 329A185C1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 329A185D1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 329A185E1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 329A185F1FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; + 329A18601FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; + 329A18611FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; + 329A18621FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; + 329A18631FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; + 329A18641FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; 32CF1C071FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32CF1C081FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32CF1C091FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1320,6 +1332,8 @@ 323F8B3D1F38EF770092B609 /* muxread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = muxread.c; sourceTree = ""; }; 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageFrame.h; sourceTree = ""; }; 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageFrame.m; sourceTree = ""; }; + 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImage+WebCache.h"; path = "SDWebImage/UIImage+WebCache.h"; sourceTree = ""; }; + 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImage+WebCache.m"; path = "SDWebImage/UIImage+WebCache.m"; sourceTree = ""; }; 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoderHelper.h; sourceTree = ""; }; 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCoderHelper.m; sourceTree = ""; }; 4314D1991D0E0E3B004B36C9 /* libSDWebImage watchOS static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libSDWebImage watchOS static.a"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1624,6 +1638,8 @@ 4369C2851D9811BB007E863A /* WebCache Categories */ = { isa = PBXGroup; children = ( + 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */, + 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */, 4397D2F41D0DE2DF00BB2784 /* NSImage+WebCache.h */, 4397D2F51D0DE2DF00BB2784 /* NSImage+WebCache.m */, 535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */, @@ -1987,6 +2003,7 @@ 80377C4A1F2F666300F89830 /* bit_writer_utils.h in Headers */, 4397D2F81D0DF44200BB2784 /* MKAnnotationView+WebCache.h in Headers */, 323F8BE71F38EF770092B609 /* vp8li_enc.h in Headers */, + 329A185C1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 4369C27A1D9807EC007E863A /* UIView+WebCache.h in Headers */, 80377DCC1F2F66A700F89830 /* lossless_common.h in Headers */, 321E60971F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, @@ -2078,6 +2095,7 @@ 80377D501F2F66A700F89830 /* mips_macro.h in Headers */, 80377C291F2F666300F89830 /* thread_utils.h in Headers */, 4314D16D1D0E0E3B004B36C9 /* SDImageCache.h in Headers */, + 329A185A1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 4314D16F1D0E0E3B004B36C9 /* NSData+ImageContentType.h in Headers */, 80377C121F2F666300F89830 /* bit_reader_inl_utils.h in Headers */, 4314D1701D0E0E3B004B36C9 /* mux.h in Headers */, @@ -2142,6 +2160,7 @@ 43A62A1B1D0E0A800089D7DD /* decode.h in Headers */, 321E608A1F38E8C800405457 /* SDWebImageCoder.h in Headers */, 80377C601F2F666400F89830 /* bit_reader_inl_utils.h in Headers */, + 329A185D1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 431BB6DC1D06D2C1006A3455 /* UIButton+WebCache.h in Headers */, 431BB6E11D06D2C1006A3455 /* SDWebImage.h in Headers */, 80377E311F2F66A800F89830 /* yuv.h in Headers */, @@ -2238,6 +2257,7 @@ 4397D2D11D0DDD8C00BB2784 /* decode.h in Headers */, 80377E481F2F66A800F89830 /* dsp.h in Headers */, 323F8BE91F38EF770092B609 /* vp8li_enc.h in Headers */, + 329A185E1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 80377E761F2F66A800F89830 /* yuv.h in Headers */, 80377C7A1F2F666400F89830 /* bit_reader_inl_utils.h in Headers */, 80377E631F2F66A800F89830 /* lossless.h in Headers */, @@ -2296,6 +2316,7 @@ 80377C301F2F666300F89830 /* bit_writer_utils.h in Headers */, 431739541CDFC8B70008FEB9 /* types.h in Headers */, 323F8BE61F38EF770092B609 /* vp8li_enc.h in Headers */, + 329A185B1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 4369C2791D9807EC007E863A /* UIView+WebCache.h in Headers */, 80377D871F2F66A700F89830 /* lossless_common.h in Headers */, 321E60961F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, @@ -2391,6 +2412,7 @@ 321E60941F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, 431738BD1CDFC2660008FEB9 /* decode.h in Headers */, 80377D0B1F2F66A100F89830 /* mips_macro.h in Headers */, + 329A18591FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 5376131A155AD0D5005750A4 /* SDWebImageDownloader.h in Headers */, 4369C2771D9807EC007E863A /* UIView+WebCache.h in Headers */, 80377CEF1F2F66A100F89830 /* dsp.h in Headers */, @@ -2794,6 +2816,7 @@ 00733A5E1BC4880000A5A117 /* UIImage+MultiFormat.m in Sources */, 80377DD01F2F66A700F89830 /* lossless_enc_neon.c in Sources */, 80377DE21F2F66A700F89830 /* rescaler.c in Sources */, + 329A18621FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, 80377DAD1F2F66A700F89830 /* argb_mips_dsp_r2.c in Sources */, 00733A601BC4880000A5A117 /* UIImageView+HighlightedWebCache.m in Sources */, 323F8BAB1F38EF770092B609 /* picture_psnr_enc.c in Sources */, @@ -2817,6 +2840,7 @@ 80377EA01F2F66D400F89830 /* vp8_dec.c in Sources */, 80377EA31F2F66D400F89830 /* vp8l_dec.c in Sources */, 80377E9D1F2F66D400F89830 /* io_dec.c in Sources */, + 329A18601FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, 80377D541F2F66A700F89830 /* rescaler_mips32.c in Sources */, 80377D331F2F66A700F89830 /* dec.c in Sources */, 323F8BAF1F38EF770092B609 /* picture_rescale_enc.c in Sources */, @@ -2960,6 +2984,7 @@ 80377ED01F2F66D500F89830 /* vp8_dec.c in Sources */, 80377ED31F2F66D500F89830 /* vp8l_dec.c in Sources */, 80377ECD1F2F66D500F89830 /* io_dec.c in Sources */, + 329A18631FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, 80377E231F2F66A800F89830 /* rescaler_mips32.c in Sources */, 80377E021F2F66A800F89830 /* dec.c in Sources */, 323F8BB21F38EF770092B609 /* picture_rescale_enc.c in Sources */, @@ -3124,6 +3149,7 @@ 80377EE01F2F66D500F89830 /* vp8_dec.c in Sources */, 32CF1C121FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */, 80377E521F2F66A800F89830 /* filters_msa.c in Sources */, + 329A18641FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, 80377C821F2F666400F89830 /* filters_utils.c in Sources */, 4397D28C1D0DDD8C00BB2784 /* UIImageView+WebCache.m in Sources */, 80377E581F2F66A800F89830 /* lossless_enc_mips32.c in Sources */, @@ -3372,6 +3398,7 @@ 43CE75801CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */, 4369C2801D9807EC007E863A /* UIView+WebCache.m in Sources */, 80377D8B1F2F66A700F89830 /* lossless_enc_neon.c in Sources */, + 329A18611FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, 80377D9D1F2F66A700F89830 /* rescaler.c in Sources */, 80377D681F2F66A700F89830 /* argb_mips_dsp_r2.c in Sources */, 323F8BAA1F38EF770092B609 /* picture_psnr_enc.c in Sources */, @@ -3519,6 +3546,7 @@ 43CE757F1CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */, 4369C27E1D9807EC007E863A /* UIView+WebCache.m in Sources */, 80377D011F2F66A100F89830 /* lossless_enc_neon.c in Sources */, + 329A185F1FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, 80377D131F2F66A100F89830 /* rescaler.c in Sources */, 80377CDE1F2F66A100F89830 /* argb_mips_dsp_r2.c in Sources */, 323F8BA81F38EF770092B609 /* picture_psnr_enc.c in Sources */, diff --git a/SDWebImage/NSImage+WebCache.h b/SDWebImage/NSImage+WebCache.h index 7515d407..1f7b888d 100644 --- a/SDWebImage/NSImage+WebCache.h +++ b/SDWebImage/NSImage+WebCache.h @@ -10,13 +10,10 @@ #if SD_MAC -#import +@interface NSImage (Additions) -@interface NSImage (WebCache) - -- (CGImageRef)CGImage; -- (NSArray *)images; -- (BOOL)isGIF; +- (nullable CGImageRef)CGImage; +- (nullable NSArray *)images; @end diff --git a/SDWebImage/NSImage+WebCache.m b/SDWebImage/NSImage+WebCache.m index 140ed6ce..b42785ea 100644 --- a/SDWebImage/NSImage+WebCache.m +++ b/SDWebImage/NSImage+WebCache.m @@ -10,7 +10,7 @@ #if SD_MAC -@implementation NSImage (WebCache) +@implementation NSImage (Additions) - (CGImageRef)CGImage { NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); @@ -22,19 +22,6 @@ return nil; } -- (BOOL)isGIF { - BOOL isGIF = NO; - for (NSImageRep *rep in self.representations) { - if ([rep isKindOfClass:[NSBitmapImageRep class]]) { - NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep; - NSUInteger frameCount = [[bitmapRep valueForProperty:NSImageFrameCount] unsignedIntegerValue]; - isGIF = frameCount > 1 ? YES : NO; - break; - } - } - return isGIF; -} - @end #endif diff --git a/SDWebImage/SDWebImageCompat.m b/SDWebImage/SDWebImageCompat.m index bb53495e..eff574ac 100644 --- a/SDWebImage/SDWebImageCompat.m +++ b/SDWebImage/SDWebImageCompat.m @@ -7,7 +7,7 @@ */ #import "SDWebImageCompat.h" -#import "UIImage+MultiFormat.h" +#import "UIImage+WebCache.h" #if !__has_feature(objc_arc) #error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag diff --git a/SDWebImage/SDWebImageFrame.h b/SDWebImage/SDWebImageFrame.h index d8ba1812..0dc2eeda 100644 --- a/SDWebImage/SDWebImageFrame.h +++ b/SDWebImage/SDWebImageFrame.h @@ -11,7 +11,7 @@ @interface SDWebImageFrame : NSObject -// This class is used for creating animated images via `animatedImageWithFrames` in `SDWebImageCoderHelper`. Attension if you need animated images loop count, use `sd_imageLoopCount` property in `UIImage+MultiFormat` +// This class is used for creating animated images via `animatedImageWithFrames` in `SDWebImageCoderHelper`. Attension if you need animated images loop count, use `sd_imageLoopCount` property in `UIImage+WebCache.h` /** The image of current frame. You should not set an animated image. diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index e05d1c0b..e2705f87 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -8,9 +8,9 @@ #import "SDWebImageGIFCoder.h" #import "NSImage+WebCache.h" +#import "UIImage+WebCache.h" #import #import "NSData+ImageContentType.h" -#import "UIImage+MultiFormat.h" #import "SDWebImageCoderHelper.h" @implementation SDWebImageGIFCoder diff --git a/SDWebImage/SDWebImageWebPCoder.m b/SDWebImage/SDWebImageWebPCoder.m index 2821c47b..d80ff445 100644 --- a/SDWebImage/SDWebImageWebPCoder.m +++ b/SDWebImage/SDWebImageWebPCoder.m @@ -11,7 +11,7 @@ #import "SDWebImageWebPCoder.h" #import "SDWebImageCoderHelper.h" #import "NSImage+WebCache.h" -#import "UIImage+MultiFormat.h" +#import "UIImage+WebCache.h" #if __has_include() && __has_include() && __has_include() && __has_include() #import #import diff --git a/SDWebImage/UIImage+GIF.h b/SDWebImage/UIImage+GIF.h index a3a66465..5748b948 100644 --- a/SDWebImage/UIImage+GIF.h +++ b/SDWebImage/UIImage+GIF.h @@ -15,11 +15,6 @@ * Creates an animated UIImage from an NSData. * For static GIF, will create an UIImage with `images` array set to nil. For animated GIF, will create an UIImage with valid `images` array. */ -+ (UIImage *)sd_animatedGIFWithData:(NSData *)data; - -/** - * Checks if an UIImage instance is a GIF. Will use the `images` array. - */ -- (BOOL)isGIF; ++ (nullable UIImage *)sd_animatedGIFWithData:(nullable NSData *)data; @end diff --git a/SDWebImage/UIImage+GIF.m b/SDWebImage/UIImage+GIF.m index 6fbca7ae..0af2ba84 100644 --- a/SDWebImage/UIImage+GIF.m +++ b/SDWebImage/UIImage+GIF.m @@ -9,7 +9,6 @@ #import "UIImage+GIF.h" #import "SDWebImageGIFCoder.h" -#import "NSImage+WebCache.h" @implementation UIImage (GIF) @@ -20,8 +19,4 @@ return [[SDWebImageGIFCoder sharedCoder] decodedImageWithData:data]; } -- (BOOL)isGIF { - return (self.images != nil); -} - @end diff --git a/SDWebImage/UIImage+MultiFormat.h b/SDWebImage/UIImage+MultiFormat.h index c0792d1b..bec411e0 100644 --- a/SDWebImage/UIImage+MultiFormat.h +++ b/SDWebImage/UIImage+MultiFormat.h @@ -11,18 +11,6 @@ @interface UIImage (MultiFormat) -/** - * UIKit: - * For static image format, this value is always 0. - * For animated image format, 0 means infinite looping. - * 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. - * AppKit: - * NSImage currently only support animated via GIF imageRep unlike UIImage. - * The getter of this property will get the loop count from GIF imageRep - * The setter of this property will set the loop count from GIF imageRep - */ -@property (nonatomic, assign) NSUInteger sd_imageLoopCount; - + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data; - (nullable NSData *)sd_imageData; - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat; diff --git a/SDWebImage/UIImage+MultiFormat.m b/SDWebImage/UIImage+MultiFormat.m index 664e0969..8abe595b 100644 --- a/SDWebImage/UIImage+MultiFormat.m +++ b/SDWebImage/UIImage+MultiFormat.m @@ -7,52 +7,10 @@ */ #import "UIImage+MultiFormat.h" - -#import "objc/runtime.h" #import "SDWebImageCodersManager.h" @implementation UIImage (MultiFormat) -#if SD_MAC -- (NSUInteger)sd_imageLoopCount { - NSUInteger imageLoopCount = 0; - for (NSImageRep *rep in self.representations) { - if ([rep isKindOfClass:[NSBitmapImageRep class]]) { - NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep; - imageLoopCount = [[bitmapRep valueForProperty:NSImageLoopCount] unsignedIntegerValue]; - break; - } - } - return imageLoopCount; -} - -- (void)setSd_imageLoopCount:(NSUInteger)sd_imageLoopCount { - for (NSImageRep *rep in self.representations) { - if ([rep isKindOfClass:[NSBitmapImageRep class]]) { - NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep; - [bitmapRep setProperty:NSImageLoopCount withValue:@(sd_imageLoopCount)]; - break; - } - } -} - -#else - -- (NSUInteger)sd_imageLoopCount { - NSUInteger imageLoopCount = 0; - NSNumber *value = objc_getAssociatedObject(self, @selector(sd_imageLoopCount)); - if ([value isKindOfClass:[NSNumber class]]) { - imageLoopCount = value.unsignedIntegerValue; - } - return imageLoopCount; -} - -- (void)setSd_imageLoopCount:(NSUInteger)sd_imageLoopCount { - NSNumber *value = @(sd_imageLoopCount); - objc_setAssociatedObject(self, @selector(sd_imageLoopCount), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} -#endif - + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data { return [[SDWebImageCodersManager sharedInstance] decodedImageWithData:data]; } diff --git a/SDWebImage/UIImage+WebCache.h b/SDWebImage/UIImage+WebCache.h new file mode 100644 index 00000000..efa1c4c6 --- /dev/null +++ b/SDWebImage/UIImage+WebCache.h @@ -0,0 +1,32 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +@interface UIImage (WebCache) + +/** + * UIKit: + * For static image format, this value is always 0. + * For animated image format, 0 means infinite looping. + * 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. + * AppKit: + * NSImage currently only support animated via GIF imageRep unlike UIImage. + * The getter of this property will get the loop count from GIF imageRep + * The setter of this property will set the loop count from GIF imageRep + */ +@property (nonatomic, assign) NSUInteger sd_imageLoopCount; +/** + * UIKit: + * Check the `images` array property + * AppKit: + * NSImage currently only support animated via GIF imageRep unlike UIImage. It will check all the imageRef + */ +@property (nonatomic, assign, readonly) BOOL sd_isAnimated; + +@end diff --git a/SDWebImage/UIImage+WebCache.m b/SDWebImage/UIImage+WebCache.m new file mode 100644 index 00000000..ed5c337f --- /dev/null +++ b/SDWebImage/UIImage+WebCache.m @@ -0,0 +1,71 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIImage+WebCache.h" +#import "objc/runtime.h" + +@implementation UIImage (WebCache) + +#if SD_MAC +- (NSUInteger)sd_imageLoopCount { + NSUInteger imageLoopCount = 0; + for (NSImageRep *rep in self.representations) { + if ([rep isKindOfClass:[NSBitmapImageRep class]]) { + NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep; + imageLoopCount = [[bitmapRep valueForProperty:NSImageLoopCount] unsignedIntegerValue]; + break; + } + } + return imageLoopCount; +} + +- (void)setSd_imageLoopCount:(NSUInteger)sd_imageLoopCount { + for (NSImageRep *rep in self.representations) { + if ([rep isKindOfClass:[NSBitmapImageRep class]]) { + NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep; + [bitmapRep setProperty:NSImageLoopCount withValue:@(sd_imageLoopCount)]; + break; + } + } +} + +- (BOOL)sd_isAnimated { + BOOL isGIF = NO; + for (NSImageRep *rep in self.representations) { + if ([rep isKindOfClass:[NSBitmapImageRep class]]) { + NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep; + NSUInteger frameCount = [[bitmapRep valueForProperty:NSImageFrameCount] unsignedIntegerValue]; + isGIF = frameCount > 1 ? YES : NO; + break; + } + } + return isGIF; +} + +#else + +- (NSUInteger)sd_imageLoopCount { + NSUInteger imageLoopCount = 0; + NSNumber *value = objc_getAssociatedObject(self, @selector(sd_imageLoopCount)); + if ([value isKindOfClass:[NSNumber class]]) { + imageLoopCount = value.unsignedIntegerValue; + } + return imageLoopCount; +} + +- (void)setSd_imageLoopCount:(NSUInteger)sd_imageLoopCount { + NSNumber *value = @(sd_imageLoopCount); + objc_setAssociatedObject(self, @selector(sd_imageLoopCount), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (BOOL)sd_isAnimated { + return (self.images != nil); +} +#endif + +@end diff --git a/SDWebImage/UIImage+WebP.h b/SDWebImage/UIImage+WebP.h index 139eebd3..cd9f27b1 100644 --- a/SDWebImage/UIImage+WebP.h +++ b/SDWebImage/UIImage+WebP.h @@ -12,17 +12,6 @@ @interface UIImage (WebP) -/** - * Get the current WebP image loop count, the default value is 0. - * For static WebP image, the value is 0. - * For animated WebP image, 0 means repeat the animation indefinitely. - * 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. - * @return WebP image loop count - * @deprecated use `sd_imageLoopCount` instead. - */ -- (NSInteger)sd_webpLoopCount __deprecated_msg("Method deprecated. Use `sd_imageLoopCount` in `UIImage+MultiFormat.h`"); - + (nullable UIImage *)sd_imageWithWebPData:(nullable NSData *)data; @end diff --git a/SDWebImage/UIImage+WebP.m b/SDWebImage/UIImage+WebP.m index 0c4a9c5c..8329d0d4 100644 --- a/SDWebImage/UIImage+WebP.m +++ b/SDWebImage/UIImage+WebP.m @@ -10,14 +10,9 @@ #import "UIImage+WebP.h" #import "SDWebImageWebPCoder.h" -#import "UIImage+MultiFormat.h" @implementation UIImage (WebP) -- (NSInteger)sd_webpLoopCount { - return self.sd_imageLoopCount; -} - + (nullable UIImage *)sd_imageWithWebPData:(nullable NSData *)data { if (!data) { return nil; diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index df3d176d..dd6f8190 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -31,6 +31,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import +#import #import #import #import From c3a35ea247d97eb139fd8c3e1fb0c9333b1e6600 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 29 Dec 2017 23:16:55 +0800 Subject: [PATCH 012/361] Remove one deprecated property `shouldUseCredentialStorage` which not used for a long time --- SDWebImage/SDWebImageDownloaderOperation.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/SDWebImage/SDWebImageDownloaderOperation.h b/SDWebImage/SDWebImageDownloaderOperation.h index bb2dc7e3..a21d02ea 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.h +++ b/SDWebImage/SDWebImageDownloaderOperation.h @@ -53,14 +53,11 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification */ @property (strong, nonatomic, readonly, nullable) NSURLSessionTask *dataTask; - -@property (assign, nonatomic) BOOL shouldDecompressImages; - /** - * Was used to determine whether the URL connection should consult the credential storage for authenticating the connection. - * @deprecated Not used for a couple of versions + * Decompressing images that are downloaded and cached can improve performance but can consume lot of memory. + * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. */ -@property (nonatomic, assign) BOOL shouldUseCredentialStorage __deprecated_msg("Property deprecated. Does nothing. Kept only for backwards compatibility"); +@property (assign, nonatomic) BOOL shouldDecompressImages; /** * The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`. From c90e100d55f37f4531df522055104fa12e0a6cbe Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 13 Jan 2018 17:11:15 +0800 Subject: [PATCH 013/361] Add missing nullability annotations --- SDWebImage/SDWebImageCompat.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index ce068071..58f443cd 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -81,11 +81,11 @@ #define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type #endif -FOUNDATION_EXPORT UIImage *SDScaledImageForKey(NSString *key, UIImage *image); +FOUNDATION_EXPORT UIImage * _Nullable SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image); typedef void(^SDWebImageNoParamsBlock)(void); -FOUNDATION_EXPORT NSString *const SDWebImageErrorDomain; +FOUNDATION_EXPORT NSString *const _Nonnull SDWebImageErrorDomain; #ifndef dispatch_queue_async_safe #define dispatch_queue_async_safe(queue, block)\ From 6797ed8be63e17d6e715d2630c718648516cab8f Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 13 Jan 2018 17:14:28 +0800 Subject: [PATCH 014/361] Update the SD_MAC define --- SDWebImage/SDWebImageCompat.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index 58f443cd..629db1bc 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -13,10 +13,9 @@ #error SDWebImage does not support Objective-C Garbage Collection #endif -// Apple's defines from TargetConditionals.h are a bit weird. // Seems like TARGET_OS_MAC is always defined (on all platforms). -// To determine if we are running on OSX, we can only rely on TARGET_OS_IPHONE=0 and all the other platforms -#if !TARGET_OS_IPHONE && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_WATCH +// To determine if we are running on macOS, use TARGET_OS_OSX in Xcode 8 +#if TARGET_OS_OSX #define SD_MAC 1 #else #define SD_MAC 0 From b6e108a5b18bc877bee0b01eabb270505f7e2554 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 13 Jan 2018 17:27:42 +0800 Subject: [PATCH 015/361] Rename `NSImage+WebCache` to `NSImage+Addtions`. Add helper methods, use property based API, which more suitable for Swift --- SDWebImage.xcodeproj/project.pbxproj | 26 +++++++---- SDWebImage/NSImage+Additions.h | 25 ++++++++++ SDWebImage/NSImage+Additions.m | 53 ++++++++++++++++++++++ SDWebImage/NSImage+WebCache.h | 20 -------- SDWebImage/NSImage+WebCache.m | 28 ------------ SDWebImage/SDImageCache.m | 2 +- SDWebImage/SDWebImageCoderHelper.m | 4 +- SDWebImage/SDWebImageCompat.m | 1 + SDWebImage/SDWebImageDownloaderOperation.m | 2 +- SDWebImage/SDWebImageGIFCoder.m | 2 +- SDWebImage/SDWebImageImageIOCoder.m | 2 +- SDWebImage/SDWebImageManager.m | 2 +- SDWebImage/SDWebImageWebPCoder.m | 2 +- SDWebImage/UIImage+WebCache.m | 51 ++++++++++++--------- WebImage/SDWebImage.h | 2 +- 15 files changed, 136 insertions(+), 86 deletions(-) create mode 100644 SDWebImage/NSImage+Additions.h create mode 100644 SDWebImage/NSImage+Additions.m delete mode 100644 SDWebImage/NSImage+WebCache.h delete mode 100644 SDWebImage/NSImage+WebCache.m diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 4618c0bb..98fce072 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -97,6 +97,11 @@ 321E60C71F38E91700405457 /* UIImage+ForceDecode.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */; }; 321E60C81F38E91700405457 /* UIImage+ForceDecode.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */; }; 321E60C91F38E91700405457 /* UIImage+ForceDecode.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */; }; + 3237F9E820161AE000A88143 /* NSImage+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */; }; + 3237F9E920161AE000A88143 /* NSImage+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */; }; + 3237F9EA20161AE000A88143 /* NSImage+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */; }; + 3237F9EB20161AE000A88143 /* NSImage+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */; }; + 3237F9EC20161AE000A88143 /* NSImage+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */; }; 323F8B3E1F38EF770092B609 /* alpha_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B131F38EF770092B609 /* alpha_enc.c */; }; 323F8B3F1F38EF770092B609 /* alpha_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B131F38EF770092B609 /* alpha_enc.c */; }; 323F8B401F38EF770092B609 /* alpha_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B131F38EF770092B609 /* alpha_enc.c */; }; @@ -488,8 +493,8 @@ 4397D2EA1D0DDD8C00BB2784 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2EB1D0DDD8C00BB2784 /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2ED1D0DDD8C00BB2784 /* mux_types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC91998E60B007367ED /* mux_types.h */; }; - 4397D2F61D0DE2DF00BB2784 /* NSImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4397D2F41D0DE2DF00BB2784 /* NSImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2F71D0DE2DF00BB2784 /* NSImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+WebCache.m */; }; + 4397D2F61D0DE2DF00BB2784 /* NSImage+Additions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4397D2F41D0DE2DF00BB2784 /* NSImage+Additions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4397D2F71D0DE2DF00BB2784 /* NSImage+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */; }; 4397D2F81D0DF44200BB2784 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2F91D0DF44A00BB2784 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */; }; 43A62A1B1D0E0A800089D7DD /* decode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC41998E60B007367ED /* decode.h */; }; @@ -1341,8 +1346,8 @@ 4369C2751D9807EC007E863A /* UIView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+WebCache.h"; path = "SDWebImage/UIView+WebCache.h"; sourceTree = ""; }; 4369C2761D9807EC007E863A /* UIView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIView+WebCache.m"; path = "SDWebImage/UIView+WebCache.m"; sourceTree = ""; }; 4397D2F21D0DDD8C00BB2784 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 4397D2F41D0DE2DF00BB2784 /* NSImage+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSImage+WebCache.h"; path = "SDWebImage/NSImage+WebCache.h"; sourceTree = ""; }; - 4397D2F51D0DE2DF00BB2784 /* NSImage+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSImage+WebCache.m"; path = "SDWebImage/NSImage+WebCache.m"; sourceTree = ""; }; + 4397D2F41D0DE2DF00BB2784 /* NSImage+Additions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImage+Additions.h"; sourceTree = ""; }; + 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSImage+Additions.m"; sourceTree = ""; }; 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageCacheConfig.h; sourceTree = ""; }; 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageCacheConfig.m; sourceTree = ""; }; 43C892981D9D6DD70022038D /* anim_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = anim_decode.c; sourceTree = ""; }; @@ -1640,8 +1645,6 @@ children = ( 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */, 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */, - 4397D2F41D0DE2DF00BB2784 /* NSImage+WebCache.h */, - 4397D2F51D0DE2DF00BB2784 /* NSImage+WebCache.m */, 535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */, 535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */, 53922D93148C56230056699D /* UIButton+WebCache.h */, @@ -1778,6 +1781,8 @@ 53EDFB921762547C00698166 /* UIImage+WebP.m */, 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */, 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */, + 4397D2F41D0DE2DF00BB2784 /* NSImage+Additions.h */, + 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */, AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */, AB615302192DA24600A2D8E9 /* UIView+WebCacheOperation.m */, ); @@ -2280,7 +2285,7 @@ 80377E661F2F66A800F89830 /* neon.h in Headers */, 4397D2DB1D0DDD8C00BB2784 /* UIImage+MultiFormat.h in Headers */, 4397D2DC1D0DDD8C00BB2784 /* SDWebImageOperation.h in Headers */, - 4397D2F61D0DE2DF00BB2784 /* NSImage+WebCache.h in Headers */, + 4397D2F61D0DE2DF00BB2784 /* NSImage+Additions.h in Headers */, 4397D2E11D0DDD8C00BB2784 /* SDWebImageDownloader.h in Headers */, 323F8BFB1F38EF770092B609 /* animi.h in Headers */, 4397D2E31D0DDD8C00BB2784 /* MKAnnotationView+WebCache.h in Headers */, @@ -2722,6 +2727,7 @@ 80377C4E1F2F666300F89830 /* filters_utils.c in Sources */, 321E60B91F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 80377DEB1F2F66A700F89830 /* yuv.c in Sources */, + 3237F9E920161AE000A88143 /* NSImage+Additions.m in Sources */, 00733A551BC4880000A5A117 /* SDWebImageDownloader.m in Sources */, 80377EB71F2F66D400F89830 /* alpha_dec.c in Sources */, 80377DC61F2F66A700F89830 /* enc.c in Sources */, @@ -2922,6 +2928,7 @@ 80377D1F1F2F66A700F89830 /* alpha_processing_neon.c in Sources */, 4314D1401D0E0E3B004B36C9 /* UIImageView+WebCache.m in Sources */, 43A9186C1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, + 3237F9EC20161AE000A88143 /* NSImage+Additions.m in Sources */, 4314D1411D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.m in Sources */, 80377D561F2F66A700F89830 /* rescaler_neon.c in Sources */, 80377D551F2F66A700F89830 /* rescaler_msa.c in Sources */, @@ -3066,6 +3073,7 @@ 323F8C0C1F38EF770092B609 /* muxedit.c in Sources */, 80377DEE1F2F66A800F89830 /* alpha_processing_neon.c in Sources */, 43C892A41D9D6DDD0022038D /* demux.c in Sources */, + 3237F9EA20161AE000A88143 /* NSImage+Additions.m in Sources */, 431BB6B61D06D2C1006A3455 /* UIImage+WebP.m in Sources */, 80377E251F2F66A800F89830 /* rescaler_neon.c in Sources */, 80377E241F2F66A800F89830 /* rescaler_msa.c in Sources */, @@ -3125,7 +3133,7 @@ 321E60911F38E8C800405457 /* SDWebImageCoder.m in Sources */, 80377C8A1F2F666400F89830 /* quant_levels_utils.c in Sources */, 4397D27F1D0DDD8C00BB2784 /* UIImage+WebP.m in Sources */, - 4397D2F71D0DE2DF00BB2784 /* NSImage+WebCache.m in Sources */, + 4397D2F71D0DE2DF00BB2784 /* NSImage+Additions.m in Sources */, 80377E751F2F66A800F89830 /* yuv.c in Sources */, 43C892A01D9D6DDA0022038D /* anim_decode.c in Sources */, 80377E4A1F2F66A800F89830 /* enc_mips_dsp_r2.c in Sources */, @@ -3304,6 +3312,7 @@ 80377DA61F2F66A700F89830 /* yuv.c in Sources */, 321E60B81F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 43CE757A1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, + 3237F9E820161AE000A88143 /* NSImage+Additions.m in Sources */, 80377D811F2F66A700F89830 /* enc.c in Sources */, 80377EA71F2F66D400F89830 /* alpha_dec.c in Sources */, 80377D8F1F2F66A700F89830 /* lossless_mips_dsp_r2.c in Sources */, @@ -3452,6 +3461,7 @@ 321E60B61F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 43CE75791CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, 80377CF71F2F66A100F89830 /* enc.c in Sources */, + 3237F9EB20161AE000A88143 /* NSImage+Additions.m in Sources */, 80377E871F2F66D000F89830 /* alpha_dec.c in Sources */, 80377D051F2F66A100F89830 /* lossless_mips_dsp_r2.c in Sources */, 80377C0A1F2F665300F89830 /* random_utils.c in Sources */, diff --git a/SDWebImage/NSImage+Additions.h b/SDWebImage/NSImage+Additions.h new file mode 100644 index 00000000..3a78ce91 --- /dev/null +++ b/SDWebImage/NSImage+Additions.h @@ -0,0 +1,25 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +// This category is provided to easily write cross-platform code. For common usage, see `UIImage+WebCache`. + +#if SD_MAC + +@interface NSImage (Additions) + +@property (nonatomic, readonly, nullable) CGImageRef CGImage; +@property (nonatomic, readonly, nullable) NSArray *images; +@property (nonatomic, readonly) CGFloat scale; + +- (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale; + +@end + +#endif diff --git a/SDWebImage/NSImage+Additions.m b/SDWebImage/NSImage+Additions.m new file mode 100644 index 00000000..466a9444 --- /dev/null +++ b/SDWebImage/NSImage+Additions.m @@ -0,0 +1,53 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "NSImage+Additions.h" + +#if SD_MAC + +@implementation NSImage (Additions) + +- (CGImageRef)CGImage { + NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); + CGImageRef cgImage = [self CGImageForProposedRect:&imageRect context:NULL hints:nil]; + return cgImage; +} + +- (NSArray *)images { + return nil; +} + +- (CGFloat)scale { + CGFloat scale = 1; + NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); + NSImageRep *rep = [self bestRepresentationForRect:imageRect context:NULL hints:nil]; + NSInteger pixelsWide = rep.pixelsWide; + CGFloat width = rep.size.width; + if (width > 0) { + scale = pixelsWide / width; + } + return scale; +} + +- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale { + NSSize size; + if (cgImage && scale > 0) { + NSInteger pixelsWide = CGImageGetWidth(cgImage); + NSInteger pixelsHigh = CGImageGetHeight(cgImage); + CGFloat width = pixelsWide / scale; + CGFloat height = pixelsHigh / scale; + size = NSMakeSize(width, height); + } else { + size = NSZeroSize; + } + return [self initWithCGImage:cgImage size:size]; +} + +@end + +#endif diff --git a/SDWebImage/NSImage+WebCache.h b/SDWebImage/NSImage+WebCache.h deleted file mode 100644 index 1f7b888d..00000000 --- a/SDWebImage/NSImage+WebCache.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * This file is part of the SDWebImage package. - * (c) Olivier Poitrey - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#import "SDWebImageCompat.h" - -#if SD_MAC - -@interface NSImage (Additions) - -- (nullable CGImageRef)CGImage; -- (nullable NSArray *)images; - -@end - -#endif diff --git a/SDWebImage/NSImage+WebCache.m b/SDWebImage/NSImage+WebCache.m deleted file mode 100644 index b42785ea..00000000 --- a/SDWebImage/NSImage+WebCache.m +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This file is part of the SDWebImage package. - * (c) Olivier Poitrey - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#import "NSImage+WebCache.h" - -#if SD_MAC - -@implementation NSImage (Additions) - -- (CGImageRef)CGImage { - NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); - CGImageRef cgImage = [self CGImageForProposedRect:&imageRect context:NULL hints:nil]; - return cgImage; -} - -- (NSArray *)images { - return nil; -} - -@end - -#endif - diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 42335732..4c027083 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -8,7 +8,7 @@ #import "SDImageCache.h" #import -#import "NSImage+WebCache.h" +#import "NSImage+Additions.h" #import "SDWebImageCodersManager.h" static void * SDImageCacheContext = &SDImageCacheContext; diff --git a/SDWebImage/SDWebImageCoderHelper.m b/SDWebImage/SDWebImageCoderHelper.m index b2b651a2..2ffcfd9a 100644 --- a/SDWebImage/SDWebImageCoderHelper.m +++ b/SDWebImage/SDWebImageCoderHelper.m @@ -8,8 +8,8 @@ #import "SDWebImageCoderHelper.h" #import "SDWebImageFrame.h" -#import "UIImage+MultiFormat.h" -#import "NSImage+WebCache.h" +#import "NSImage+Additions.h" +#import "NSData+ImageContentType.h" #import @implementation SDWebImageCoderHelper diff --git a/SDWebImage/SDWebImageCompat.m b/SDWebImage/SDWebImageCompat.m index eff574ac..b3377e6a 100644 --- a/SDWebImage/SDWebImageCompat.m +++ b/SDWebImage/SDWebImageCompat.m @@ -8,6 +8,7 @@ #import "SDWebImageCompat.h" #import "UIImage+WebCache.h" +#import "NSImage+Additions.h" #if !__has_feature(objc_arc) #error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 553b0e95..cffb1a86 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -8,7 +8,7 @@ #import "SDWebImageDownloaderOperation.h" #import "SDWebImageManager.h" -#import "NSImage+WebCache.h" +#import "NSImage+Additions.h" #import "SDWebImageCodersManager.h" NSString *const SDWebImageDownloadStartNotification = @"SDWebImageDownloadStartNotification"; diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index e2705f87..b8c9c4b2 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -7,7 +7,7 @@ */ #import "SDWebImageGIFCoder.h" -#import "NSImage+WebCache.h" +#import "NSImage+Additions.h" #import "UIImage+WebCache.h" #import #import "NSData+ImageContentType.h" diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index baf3cfdf..570e2a11 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -8,7 +8,7 @@ #import "SDWebImageImageIOCoder.h" #import "SDWebImageCoderHelper.h" -#import "NSImage+WebCache.h" +#import "NSImage+Additions.h" #import #import "NSData+ImageContentType.h" diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 36ab073b..645bf506 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -7,7 +7,7 @@ */ #import "SDWebImageManager.h" -#import "NSImage+WebCache.h" +#import "NSImage+Additions.h" #import @interface SDWebImageCombinedOperation : NSObject diff --git a/SDWebImage/SDWebImageWebPCoder.m b/SDWebImage/SDWebImageWebPCoder.m index d80ff445..3f68c1c5 100644 --- a/SDWebImage/SDWebImageWebPCoder.m +++ b/SDWebImage/SDWebImageWebPCoder.m @@ -10,7 +10,7 @@ #import "SDWebImageWebPCoder.h" #import "SDWebImageCoderHelper.h" -#import "NSImage+WebCache.h" +#import "NSImage+Additions.h" #import "UIImage+WebCache.h" #if __has_include() && __has_include() && __has_include() && __has_include() #import diff --git a/SDWebImage/UIImage+WebCache.m b/SDWebImage/UIImage+WebCache.m index ed5c337f..60d3e2f7 100644 --- a/SDWebImage/UIImage+WebCache.m +++ b/SDWebImage/UIImage+WebCache.m @@ -7,11 +7,39 @@ */ #import "UIImage+WebCache.h" + +#if SD_UIKIT + #import "objc/runtime.h" @implementation UIImage (WebCache) +- (NSUInteger)sd_imageLoopCount { + NSUInteger imageLoopCount = 0; + NSNumber *value = objc_getAssociatedObject(self, @selector(sd_imageLoopCount)); + if ([value isKindOfClass:[NSNumber class]]) { + imageLoopCount = value.unsignedIntegerValue; + } + return imageLoopCount; +} + +- (void)setSd_imageLoopCount:(NSUInteger)sd_imageLoopCount { + NSNumber *value = @(sd_imageLoopCount); + objc_setAssociatedObject(self, @selector(sd_imageLoopCount), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (BOOL)sd_isAnimated { + return (self.images != nil); +} + +@end + +#endif + #if SD_MAC + +@implementation NSImage (WebCache) + - (NSUInteger)sd_imageLoopCount { NSUInteger imageLoopCount = 0; for (NSImageRep *rep in self.representations) { @@ -47,25 +75,6 @@ return isGIF; } -#else - -- (NSUInteger)sd_imageLoopCount { - NSUInteger imageLoopCount = 0; - NSNumber *value = objc_getAssociatedObject(self, @selector(sd_imageLoopCount)); - if ([value isKindOfClass:[NSNumber class]]) { - imageLoopCount = value.unsignedIntegerValue; - } - return imageLoopCount; -} - -- (void)setSd_imageLoopCount:(NSUInteger)sd_imageLoopCount { - NSNumber *value = @(sd_imageLoopCount); - objc_setAssociatedObject(self, @selector(sd_imageLoopCount), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (BOOL)sd_isAnimated { - return (self.images != nil); -} -#endif - @end + +#endif diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index dd6f8190..22258eba 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -53,7 +53,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #if SD_MAC - #import + #import #endif #if SD_UIKIT From dc5d7d189d44c57c929cb878129943dddb3dbd8a Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 28 Dec 2017 16:06:37 +0800 Subject: [PATCH 016/361] Rename UIImage+ForceDecode method with sd prefix to avoid name conflict --- SDWebImage/UIImage+ForceDecode.h | 4 ++-- SDWebImage/UIImage+ForceDecode.m | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SDWebImage/UIImage+ForceDecode.h b/SDWebImage/UIImage+ForceDecode.h index 708c37b0..e8ef5340 100644 --- a/SDWebImage/UIImage+ForceDecode.h +++ b/SDWebImage/UIImage+ForceDecode.h @@ -10,8 +10,8 @@ @interface UIImage (ForceDecode) -+ (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image; ++ (nullable UIImage *)sd_decodedImageWithImage:(nullable UIImage *)image; -+ (nullable UIImage *)decodedAndScaledDownImageWithImage:(nullable UIImage *)image; ++ (nullable UIImage *)sd_decodedAndScaledDownImageWithImage:(nullable UIImage *)image; @end diff --git a/SDWebImage/UIImage+ForceDecode.m b/SDWebImage/UIImage+ForceDecode.m index ee55aee7..2f25f047 100644 --- a/SDWebImage/UIImage+ForceDecode.m +++ b/SDWebImage/UIImage+ForceDecode.m @@ -11,7 +11,7 @@ @implementation UIImage (ForceDecode) -+ (UIImage *)decodedImageWithImage:(UIImage *)image { ++ (UIImage *)sd_decodedImageWithImage:(UIImage *)image { if (!image) { return nil; } @@ -19,7 +19,7 @@ return [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&tempData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}]; } -+ (UIImage *)decodedAndScaledDownImageWithImage:(UIImage *)image { ++ (UIImage *)sd_decodedAndScaledDownImageWithImage:(UIImage *)image { if (!image) { return nil; } From 82c44e275a6d33010ca0a87dd3c867e749e91e0a Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 13 Jan 2018 17:38:29 +0800 Subject: [PATCH 017/361] Update the test --- Tests/Tests/SDWebImageDecoderTests.m | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Tests/Tests/SDWebImageDecoderTests.m b/Tests/Tests/SDWebImageDecoderTests.m index 0ceaff3d..947548c8 100644 --- a/Tests/Tests/SDWebImageDecoderTests.m +++ b/Tests/Tests/SDWebImageDecoderTests.m @@ -21,13 +21,13 @@ @implementation SDWebImageDecoderTests - (void)test01ThatDecodedImageWithNilImageReturnsNil { - expect([UIImage decodedImageWithImage:nil]).to.beNil(); + expect([UIImage sd_decodedImageWithImage:nil]).to.beNil(); } - (void)test02ThatDecodedImageWithImageWorksWithARegularJPGImage { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"jpg"]; UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; - UIImage *decodedImage = [UIImage decodedImageWithImage:image]; + UIImage *decodedImage = [UIImage sd_decodedImageWithImage:image]; expect(decodedImage).toNot.beNil(); expect(decodedImage).toNot.equal(image); expect(decodedImage.size.width).to.equal(image.size.width); @@ -38,7 +38,7 @@ NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"gif"]; UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; UIImage *animatedImage = [UIImage animatedImageWithImages:@[image] duration:0]; - UIImage *decodedImage = [UIImage decodedImageWithImage:animatedImage]; + UIImage *decodedImage = [UIImage sd_decodedImageWithImage:animatedImage]; expect(decodedImage).toNot.beNil(); expect(decodedImage).to.equal(animatedImage); } @@ -46,7 +46,7 @@ - (void)test04ThatDecodedImageWithImageDoesNotDecodeImagesWithAlpha { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"png"]; UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; - UIImage *decodedImage = [UIImage decodedImageWithImage:image]; + UIImage *decodedImage = [UIImage sd_decodedImageWithImage:image]; expect(decodedImage).toNot.beNil(); expect(decodedImage).to.equal(image); } @@ -54,7 +54,7 @@ - (void)test05ThatDecodedImageWithImageWorksEvenWithMonochromeImage { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"MonochromeTestImage" ofType:@"jpg"]; UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; - UIImage *decodedImage = [UIImage decodedImageWithImage:image]; + UIImage *decodedImage = [UIImage sd_decodedImageWithImage:image]; expect(decodedImage).toNot.beNil(); expect(decodedImage).toNot.equal(image); expect(decodedImage.size.width).to.equal(image.size.width); @@ -64,7 +64,7 @@ - (void)test06ThatDecodeAndScaleDownImageWorks { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImageLarge" ofType:@"jpg"]; UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; - UIImage *decodedImage = [UIImage decodedAndScaledDownImageWithImage:image]; + UIImage *decodedImage = [UIImage sd_decodedAndScaledDownImageWithImage:image]; expect(decodedImage).toNot.beNil(); expect(decodedImage).toNot.equal(image); expect(decodedImage.size.width).toNot.equal(image.size.width); @@ -75,7 +75,7 @@ - (void)test07ThatDecodeAndScaleDownImageDoesNotScaleSmallerImage { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"jpg"]; UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; - UIImage *decodedImage = [UIImage decodedAndScaledDownImageWithImage:image]; + UIImage *decodedImage = [UIImage sd_decodedAndScaledDownImageWithImage:image]; expect(decodedImage).toNot.beNil(); expect(decodedImage).toNot.equal(image); expect(decodedImage.size.width).to.equal(image.size.width); From 6f6f54e6c55154ae69e8d835ff2eba1ba590b2d4 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 16 Jan 2018 00:06:18 +0800 Subject: [PATCH 018/361] Mark one function which return value should follow the GET rule --- SDWebImage/NSData+ImageContentType.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/NSData+ImageContentType.h b/SDWebImage/NSData+ImageContentType.h index 0ca226d8..1eaab8dc 100644 --- a/SDWebImage/NSData+ImageContentType.h +++ b/SDWebImage/NSData+ImageContentType.h @@ -37,6 +37,6 @@ typedef NS_ENUM(NSInteger, SDImageFormat) { @param format Format as SDImageFormat @return The UTType as CFStringRef */ -+ (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format; ++ (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format CF_RETURNS_NOT_RETAINED; @end From 9e48da8a8a747ab24b162d0361bad422b63c27f0 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 16 Jan 2018 00:15:15 +0800 Subject: [PATCH 019/361] Update and remove the deprecated method. Add some documents for un-documented methods --- SDWebImage/UIImage+ForceDecode.h | 12 ++++++++++++ SDWebImage/UIImage+MultiFormat.h | 19 +++++++++++++++++++ SDWebImage/UIImageView+WebCache.h | 28 +++------------------------- SDWebImage/UIImageView+WebCache.m | 11 ----------- SDWebImage/UIView+WebCache.h | 2 +- SDWebImage/UIView+WebCache.m | 6 +++++- 6 files changed, 40 insertions(+), 38 deletions(-) diff --git a/SDWebImage/UIImage+ForceDecode.h b/SDWebImage/UIImage+ForceDecode.h index e8ef5340..ae85114b 100644 --- a/SDWebImage/UIImage+ForceDecode.h +++ b/SDWebImage/UIImage+ForceDecode.h @@ -10,8 +10,20 @@ @interface UIImage (ForceDecode) +/** + Decompress (force decode before rendering) the provided image + + @param image The image to be decompressed + @return The decompressed image + */ + (nullable UIImage *)sd_decodedImageWithImage:(nullable UIImage *)image; +/** + Decompress and scale down the provided image + + @param image The image to be decompressed + @return The decompressed and scaled down image + */ + (nullable UIImage *)sd_decodedAndScaledDownImageWithImage:(nullable UIImage *)image; @end diff --git a/SDWebImage/UIImage+MultiFormat.h b/SDWebImage/UIImage+MultiFormat.h index bec411e0..f316fe96 100644 --- a/SDWebImage/UIImage+MultiFormat.h +++ b/SDWebImage/UIImage+MultiFormat.h @@ -11,8 +11,27 @@ @interface UIImage (MultiFormat) +/** + Create and decode a image with the specify image data + + @param data The image data + @return The created image + */ + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data; + +/** + Encode the current image to the data, the image format is unspecified + + @return The encoded data. If can't encode, return nil + */ - (nullable NSData *)sd_imageData; + +/** + Encode the current image to data with the specify image format + + @param imageFormat The specify image format + @return The encoded data. If can't encode, return nil + */ - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat; @end diff --git a/SDWebImage/UIImageView+WebCache.h b/SDWebImage/UIImageView+WebCache.h index ef2eacfd..7b7d530d 100644 --- a/SDWebImage/UIImageView+WebCache.h +++ b/SDWebImage/UIImageView+WebCache.h @@ -154,31 +154,6 @@ progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; -/** - * Set the imageView `image` with an `url` and custom options. The placeholder image is from previous cached image and will use the provided one instead if the query failed. - * This method was designed to ensure that placeholder and query cache process happened in the same runloop to avoid flashing on cell during two `setImage:` call. But it's really misunderstanding and deprecated. - * This can be done by using `sd_setImageWithURL:` with `SDWebImageQueryDiskSync`. But take care that if the memory cache missed, query disk cache synchronously may reduce the frame rate - * - * The download is asynchronous and cached. - * - * @param url The url for the image. - * @param placeholder The image to be set initially, until the image request finishes. - * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. - * @param progressBlock A block called while image is downloading - * @note the progress block is executed on a background queue - * @param completedBlock A block called when operation has been completed. This block has no return value - * and takes the requested UIImage as first parameter. In case of error the image parameter - * is nil and the second parameter may contain an NSError. The third parameter is a Boolean - * indicating if the image was retrieved from the local cache or from the network. - * The fourth parameter is the original image url. - * @deprecated consider using `SDWebImageQueryDiskSync` options with `sd_setImageWithURL:` instead - */ -- (void)sd_setImageWithPreviousCachedImageWithURL:(nullable NSURL *)url - placeholderImage:(nullable UIImage *)placeholder - options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDExternalCompletionBlock)completedBlock __deprecated_msg("This method is misunderstanding and deprecated, consider using `SDWebImageQueryDiskSync` options with `sd_setImageWithURL:` instead"); - #if SD_UIKIT #pragma mark - Animation of multiple images @@ -190,6 +165,9 @@ */ - (void)sd_setAnimationImagesWithURLs:(nonnull NSArray *)arrayOfURLs; +/** + * Cancel the current animation images load + */ - (void)sd_cancelCurrentAnimationImagesLoad; #endif diff --git a/SDWebImage/UIImageView+WebCache.m b/SDWebImage/UIImageView+WebCache.m index aa8ce431..cc9b476d 100644 --- a/SDWebImage/UIImageView+WebCache.m +++ b/SDWebImage/UIImageView+WebCache.m @@ -54,17 +54,6 @@ completed:completedBlock]; } -- (void)sd_setImageWithPreviousCachedImageWithURL:(nullable NSURL *)url - placeholderImage:(nullable UIImage *)placeholder - options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDExternalCompletionBlock)completedBlock { - NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:url]; - UIImage *lastPreviousCachedImage = [[SDImageCache sharedImageCache] imageFromCacheForKey:key]; - - [self sd_setImageWithURL:url placeholderImage:lastPreviousCachedImage ?: placeholder options:options progress:progressBlock completed:completedBlock]; -} - #if SD_UIKIT #pragma mark - Animation of multiple images diff --git a/SDWebImage/UIView+WebCache.h b/SDWebImage/UIView+WebCache.h index 941d0f3a..dea29aa9 100644 --- a/SDWebImage/UIView+WebCache.h +++ b/SDWebImage/UIView+WebCache.h @@ -34,7 +34,7 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima * * @note Note that because of the limitations of categories this property can get out of sync if you use setImage: directly. */ -- (nullable NSURL *)sd_imageURL; +@property (nonatomic, strong, readonly, nullable) NSURL *sd_imageURL; /** * The current image loading progress associated to the view. The unit count is the received size and excepted size of download. diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index d4cc8984..c12baeaa 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -32,6 +32,10 @@ static char TAG_ACTIVITY_SHOW; return objc_getAssociatedObject(self, &imageURLKey); } +- (void)setSd_imageURL:(NSURL * _Nullable)sd_imageURL { + objc_setAssociatedObject(self, &imageURLKey, sd_imageURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + - (NSProgress *)sd_imageProgress { NSProgress *progress = objc_getAssociatedObject(self, @selector(sd_imageProgress)); if (!progress) { @@ -65,7 +69,7 @@ static char TAG_ACTIVITY_SHOW; context:(nullable NSDictionary *)context { NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]); [self sd_cancelImageLoadOperationWithKey:validOperationKey]; - objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + self.sd_imageURL = url; if (!(options & SDWebImageDelayPlaceholder)) { if ([context valueForKey:SDWebImageInternalSetImageGroupKey]) { From d4daca3c1271b768c2dd4b4a212872f10711a407 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 21 Jan 2018 23:26:47 +0800 Subject: [PATCH 020/361] Change our SDScaledImageForKey to use scale on macOS --- SDWebImage/SDWebImageCompat.m | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/SDWebImage/SDWebImageCompat.m b/SDWebImage/SDWebImageCompat.m index b3377e6a..35dedc42 100644 --- a/SDWebImage/SDWebImageCompat.m +++ b/SDWebImage/SDWebImageCompat.m @@ -23,9 +23,7 @@ inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullabl return nil; } -#if SD_MAC - return image; -#elif SD_UIKIT || SD_WATCH +#if SD_UIKIT || SD_WATCH if ((image.images).count > 0) { NSMutableArray *scaledImages = [NSMutableArray array]; @@ -39,10 +37,13 @@ inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullabl } return animatedImage; } else { +#endif #if SD_WATCH if ([[WKInterfaceDevice currentDevice] respondsToSelector:@selector(screenScale)]) { #elif SD_UIKIT if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) { +#elif SD_MAC + if ([[NSScreen mainScreen] respondsToSelector:@selector(backingScaleFactor)]) { #endif CGFloat scale = 1; if (key.length >= 8) { @@ -56,11 +57,17 @@ inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullabl scale = 3.0; } } - - UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; - image = scaledImage; + if (scale > 1) { +#if SD_UIKIT || SD_WATCH + UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; +#else + UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale]; +#endif + image = scaledImage; + } } return image; +#if SD_UIKIT || SD_WATCH } #endif } From eedc0ad20c4b8e4ea2a9abc35e3f02bf7e1e89b2 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 13 Jan 2018 18:42:15 +0800 Subject: [PATCH 021/361] Move the context option to a separate header to allow to be included without dependency, use String Enum to bridge for Swift --- SDWebImage.xcodeproj/project.pbxproj | 28 +++++++++++++++++++ .../FLAnimatedImageView+WebCache.m | 2 +- SDWebImage/SDImageCache.h | 1 + SDWebImage/SDWebImageCompat.h | 2 -- SDWebImage/SDWebImageDefine.h | 22 +++++++++++++++ SDWebImage/SDWebImageDefine.m | 12 ++++++++ SDWebImage/SDWebImageDownloader.h | 1 + SDWebImage/UIView+WebCache.h | 13 ++------- SDWebImage/UIView+WebCache.m | 17 +++++------ WebImage/SDWebImage.h | 1 + 10 files changed, 76 insertions(+), 23 deletions(-) create mode 100644 SDWebImage/SDWebImageDefine.h create mode 100644 SDWebImage/SDWebImageDefine.m diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 98fce072..a6e7779e 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -312,6 +312,18 @@ 323F8C1D1F38EF770092B609 /* muxread.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3D1F38EF770092B609 /* muxread.c */; }; 323F8C1E1F38EF770092B609 /* muxread.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3D1F38EF770092B609 /* muxread.c */; }; 323F8C1F1F38EF770092B609 /* muxread.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3D1F38EF770092B609 /* muxread.c */; }; + 324DF4B4200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 324DF4B5200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 324DF4B6200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 324DF4B7200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 324DF4B8200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 324DF4B9200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 324DF4BA200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; }; + 324DF4BB200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; }; + 324DF4BC200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; }; + 324DF4BD200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; }; + 324DF4BE200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; }; + 324DF4BF200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; }; 3290FA041FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3290FA051FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3290FA061FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1335,6 +1347,8 @@ 323F8B3B1F38EF770092B609 /* muxi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = muxi.h; sourceTree = ""; }; 323F8B3C1F38EF770092B609 /* muxinternal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = muxinternal.c; sourceTree = ""; }; 323F8B3D1F38EF770092B609 /* muxread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = muxread.c; sourceTree = ""; }; + 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDefine.h; sourceTree = ""; }; + 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDefine.m; sourceTree = ""; }; 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageFrame.h; sourceTree = ""; }; 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageFrame.m; sourceTree = ""; }; 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImage+WebCache.h"; path = "SDWebImage/UIImage+WebCache.h"; sourceTree = ""; }; @@ -1818,6 +1832,8 @@ 53922D8F148C56230056699D /* SDWebImageManager.m */, 53922D91148C56230056699D /* SDWebImagePrefetcher.h */, 53922D92148C56230056699D /* SDWebImagePrefetcher.m */, + 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */, + 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */, ); name = Utils; sourceTree = ""; @@ -2018,6 +2034,7 @@ 323F8B711F38EF770092B609 /* delta_palettization_enc.h in Headers */, 321E60B31F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 3290FA071FA478AF0047D20C /* SDWebImageFrame.h in Headers */, + 324DF4B7200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 807A122B1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, 80377EC61F2F66D500F89830 /* webpi_dec.h in Headers */, 80377C591F2F666300F89830 /* random_utils.h in Headers */, @@ -2125,6 +2142,7 @@ 80377E981F2F66D400F89830 /* alphai_dec.h in Headers */, 4314D1791D0E0E3B004B36C9 /* SDWebImageManager.h in Headers */, 323F8BE51F38EF770092B609 /* vp8li_enc.h in Headers */, + 324DF4B5200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 80377C191F2F666300F89830 /* endian_inl_utils.h in Headers */, 321E60A31F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, 4314D17C1D0E0E3B004B36C9 /* UIImage+WebP.h in Headers */, @@ -2207,6 +2225,7 @@ 321E60981F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, 4369C27B1D9807EC007E863A /* UIView+WebCache.h in Headers */, 80377ED11F2F66D500F89830 /* vp8_dec.h in Headers */, + 324DF4B8200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 80377C751F2F666400F89830 /* rescaler_utils.h in Headers */, 80377C6F1F2F666400F89830 /* quant_levels_dec_utils.h in Headers */, 431BB6F01D06D2C1006A3455 /* SDWebImageOperation.h in Headers */, @@ -2235,6 +2254,7 @@ 80377C7E1F2F666400F89830 /* bit_writer_utils.h in Headers */, 80377ED81F2F66D500F89830 /* alphai_dec.h in Headers */, 321E60A71F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, + 324DF4B9200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 80377EDA1F2F66D500F89830 /* common_dec.h in Headers */, 80377EE61F2F66D500F89830 /* webpi_dec.h in Headers */, 4397D2BA1D0DDD8C00BB2784 /* demux.h in Headers */, @@ -2331,6 +2351,7 @@ 323F8B701F38EF770092B609 /* delta_palettization_enc.h in Headers */, 321E60B21F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 3290FA061FA478AF0047D20C /* SDWebImageFrame.h in Headers */, + 324DF4B6200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 807A122A1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, 80377EB61F2F66D400F89830 /* webpi_dec.h in Headers */, 4A2CAE211AB4BB7000B6BC39 /* SDWebImageManager.h in Headers */, @@ -2428,6 +2449,7 @@ 80377C0F1F2F665300F89830 /* thread_utils.h in Headers */, 321E60BE1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 5376131E155AD0D5005750A4 /* SDWebImagePrefetcher.h in Headers */, + 324DF4B4200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 80377CE11F2F66A100F89830 /* common_sse2.h in Headers */, 80377C0B1F2F665300F89830 /* random_utils.h in Headers */, 80377E921F2F66D000F89830 /* vp8i_dec.h in Headers */, @@ -2804,6 +2826,7 @@ 80377C521F2F666300F89830 /* huffman_utils.c in Sources */, 80377DD81F2F66A700F89830 /* lossless.c in Sources */, 80377DE11F2F66A700F89830 /* rescaler_sse2.c in Sources */, + 324DF4BD200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 80377DAC1F2F66A700F89830 /* alpha_processing.c in Sources */, 80377DE01F2F66A700F89830 /* rescaler_neon.c in Sources */, 80377C541F2F666300F89830 /* quant_levels_dec_utils.c in Sources */, @@ -2942,6 +2965,7 @@ 80377D5C1F2F66A700F89830 /* upsampling_sse2.c in Sources */, 323F8BC71F38EF770092B609 /* syntax_enc.c in Sources */, 80377D321F2F66A700F89830 /* dec_sse41.c in Sources */, + 324DF4BB200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 80377D451F2F66A700F89830 /* lossless_enc_msa.c in Sources */, 80377C1A1F2F666300F89830 /* filters_utils.c in Sources */, 323F8B9D1F38EF770092B609 /* picture_csp_enc.c in Sources */, @@ -3087,6 +3111,7 @@ 80377DFD1F2F66A800F89830 /* dec_mips32.c in Sources */, 323F8BCA1F38EF770092B609 /* syntax_enc.c in Sources */, 80377E2B1F2F66A800F89830 /* upsampling_sse2.c in Sources */, + 324DF4BE200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 80377E011F2F66A800F89830 /* dec_sse41.c in Sources */, 80377E141F2F66A800F89830 /* lossless_enc_msa.c in Sources */, 323F8BA01F38EF770092B609 /* picture_csp_enc.c in Sources */, @@ -3159,6 +3184,7 @@ 80377E521F2F66A800F89830 /* filters_msa.c in Sources */, 329A18641FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, 80377C821F2F666400F89830 /* filters_utils.c in Sources */, + 324DF4BF200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 4397D28C1D0DDD8C00BB2784 /* UIImageView+WebCache.m in Sources */, 80377E581F2F66A800F89830 /* lossless_enc_mips32.c in Sources */, 4397D28F1D0DDD8C00BB2784 /* SDWebImageDownloaderOperation.m in Sources */, @@ -3389,6 +3415,7 @@ 80377EB01F2F66D400F89830 /* vp8_dec.c in Sources */, 80377C381F2F666300F89830 /* huffman_utils.c in Sources */, 80377C3A1F2F666300F89830 /* quant_levels_dec_utils.c in Sources */, + 324DF4BC200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 80377D931F2F66A700F89830 /* lossless.c in Sources */, 80377D9C1F2F66A700F89830 /* rescaler_sse2.c in Sources */, 80377D671F2F66A700F89830 /* alpha_processing.c in Sources */, @@ -3538,6 +3565,7 @@ 80377C041F2F665300F89830 /* huffman_utils.c in Sources */, 80377C061F2F665300F89830 /* quant_levels_dec_utils.c in Sources */, 80377D091F2F66A100F89830 /* lossless.c in Sources */, + 324DF4BA200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 80377D121F2F66A100F89830 /* rescaler_sse2.c in Sources */, 80377CDD1F2F66A100F89830 /* alpha_processing.c in Sources */, 80377D111F2F66A100F89830 /* rescaler_neon.c in Sources */, diff --git a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m index 84df3e1f..eb302fbd 100644 --- a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m +++ b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m @@ -107,7 +107,7 @@ } progress:progressBlock completed:completedBlock - context:group ? @{SDWebImageInternalSetImageGroupKey : group} : nil]; + context:group ? @{SDWebImageContextSetImageGroup : group} : nil]; } @end diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 8ba73e62..cce20261 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -8,6 +8,7 @@ #import #import "SDWebImageCompat.h" +#import "SDWebImageDefine.h" #import "SDImageCacheConfig.h" typedef NS_ENUM(NSInteger, SDImageCacheType) { diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index 629db1bc..adbc64d2 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -82,8 +82,6 @@ FOUNDATION_EXPORT UIImage * _Nullable SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image); -typedef void(^SDWebImageNoParamsBlock)(void); - FOUNDATION_EXPORT NSString *const _Nonnull SDWebImageErrorDomain; #ifndef dispatch_queue_async_safe diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h new file mode 100644 index 00000000..d99d22d4 --- /dev/null +++ b/SDWebImage/SDWebImageDefine.h @@ -0,0 +1,22 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import + +typedef void(^SDWebImageNoParamsBlock)(void); +typedef NSString * SDWebImageContextOption NS_STRING_ENUM; +typedef NSDictionary SDWebImageContext; + +/** + A Dispatch group to maintain setImageBlock and completionBlock. This is used for custom setImageBlock advanced usage, such like perform background task but need to guarantee the completion block is called after setImageBlock. (dispatch_group_t) + */ +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextSetImageGroup; +/** + A SDWebImageManager instance to control the image download and cache process using in UIImageView+WebCache category and likes. If not provided, use the shared manager (SDWebImageManager) + */ +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustomManager; diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m new file mode 100644 index 00000000..36adffae --- /dev/null +++ b/SDWebImage/SDWebImageDefine.m @@ -0,0 +1,12 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageDefine.h" + +SDWebImageContextOption const SDWebImageContextSetImageGroup = @"setImageGroup"; +SDWebImageContextOption const SDWebImageContextCustomManager = @"customManager"; diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 54224c5c..3f88a41d 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -8,6 +8,7 @@ #import #import "SDWebImageCompat.h" +#import "SDWebImageDefine.h" #import "SDWebImageOperation.h" typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { diff --git a/SDWebImage/UIView+WebCache.h b/SDWebImage/UIView+WebCache.h index dea29aa9..530138df 100644 --- a/SDWebImage/UIView+WebCache.h +++ b/SDWebImage/UIView+WebCache.h @@ -10,16 +10,9 @@ #if SD_UIKIT || SD_MAC +#import "SDWebImageDefine.h" #import "SDWebImageManager.h" -/** - A Dispatch group to maintain setImageBlock and completionBlock. This key should be used only internally and may be changed in the future. (dispatch_group_t) - */ -FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageInternalSetImageGroupKey; -/** - A SDWebImageManager instance to control the image download and cache process using in UIImageView+WebCache category and likes. If not provided, use the shared manager (SDWebImageManager) - */ -FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageExternalCustomManagerKey; /** The value specify that the image progress unit count cannot be determined because the progressBlock is not been called. */ @@ -88,7 +81,7 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. - * @param context A context with extra information to perform specify changes or processes. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. */ - (void)sd_internalSetImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder @@ -97,7 +90,7 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima setImageBlock:(nullable SDSetImageBlock)setImageBlock progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock - context:(nullable NSDictionary *)context; + context:(nullable SDWebImageContext *)context; /** * Cancel the current image load diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index c12baeaa..613a5cd5 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -13,9 +13,6 @@ #import "objc/runtime.h" #import "UIView+WebCacheOperation.h" -NSString * const SDWebImageInternalSetImageGroupKey = @"internalSetImageGroup"; -NSString * const SDWebImageExternalCustomManagerKey = @"externalCustomManager"; - const int64_t SDWebImageProgressUnitCountUnknown = 1LL; static char imageURLKey; @@ -66,14 +63,14 @@ static char TAG_ACTIVITY_SHOW; setImageBlock:(nullable SDSetImageBlock)setImageBlock progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock - context:(nullable NSDictionary *)context { + context:(nullable SDWebImageContext *)context { NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]); [self sd_cancelImageLoadOperationWithKey:validOperationKey]; self.sd_imageURL = url; if (!(options & SDWebImageDelayPlaceholder)) { - if ([context valueForKey:SDWebImageInternalSetImageGroupKey]) { - dispatch_group_t group = [context valueForKey:SDWebImageInternalSetImageGroupKey]; + if ([context valueForKey:SDWebImageContextSetImageGroup]) { + dispatch_group_t group = [context valueForKey:SDWebImageContextSetImageGroup]; dispatch_group_enter(group); } dispatch_main_async_safe(^{ @@ -92,8 +89,8 @@ static char TAG_ACTIVITY_SHOW; self.sd_imageProgress.completedUnitCount = 0; SDWebImageManager *manager; - if ([context valueForKey:SDWebImageExternalCustomManagerKey]) { - manager = (SDWebImageManager *)[context valueForKey:SDWebImageExternalCustomManagerKey]; + if ([context valueForKey:SDWebImageContextCustomManager]) { + manager = (SDWebImageManager *)[context valueForKey:SDWebImageContextCustomManager]; } else { manager = [SDWebImageManager sharedManager]; } @@ -148,8 +145,8 @@ static char TAG_ACTIVITY_SHOW; targetData = nil; } - if ([context valueForKey:SDWebImageInternalSetImageGroupKey]) { - dispatch_group_t group = [context valueForKey:SDWebImageInternalSetImageGroupKey]; + if ([context valueForKey:SDWebImageContextSetImageGroup]) { + dispatch_group_t group = [context valueForKey:SDWebImageContextSetImageGroup]; dispatch_group_enter(group); dispatch_main_async_safe(^{ [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock]; diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index 22258eba..0f74183e 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -51,6 +51,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import +#import #if SD_MAC #import From a2f760c7bebbec253bf7a921715c2d270307d57e Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 23 Jan 2018 20:45:31 +0800 Subject: [PATCH 022/361] Pass the context arg from the top level to the bottom level to allow specify logic in the future --- SDWebImage/SDImageCache.h | 12 ++++++++++++ SDWebImage/SDImageCache.m | 8 ++++++-- SDWebImage/SDWebImageDownloader.h | 22 ++++++++++++++++++++++ SDWebImage/SDWebImageDownloader.m | 7 ++++++- SDWebImage/SDWebImageDownloaderOperation.h | 14 +++++++++++--- SDWebImage/SDWebImageDownloaderOperation.m | 2 ++ SDWebImage/SDWebImageManager.h | 18 ++++++++++++++++++ SDWebImage/SDWebImageManager.m | 17 +++++++++++------ SDWebImage/UIView+WebCache.m | 2 +- 9 files changed, 89 insertions(+), 13 deletions(-) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index cce20261..17ec5af4 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -204,6 +204,18 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er */ - (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock; +/** + * Asynchronously queries the cache with operation and call the completion when done. + * + * @param key The unique key used to store the wanted image + * @param options A mask to specify options to use for this cache query + * @param doneBlock The completion block. Will not get called if the operation is cancelled + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * + * @return a NSOperation instance containing the cache op + */ +- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock context:(nullable SDWebImageContext *)context; + /** * Synchronously query the memory cache. * diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 4c027083..25e75c27 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -385,11 +385,15 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { return SDScaledImageForKey(key, image); } -- (NSOperation *)queryCacheOperationForKey:(NSString *)key done:(SDCacheQueryCompletedBlock)doneBlock { +- (nullable NSOperation *)queryCacheOperationForKey:(NSString *)key done:(SDCacheQueryCompletedBlock)doneBlock { return [self queryCacheOperationForKey:key options:0 done:doneBlock]; } -- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock { +- (nullable NSOperation *)queryCacheOperationForKey:(NSString *)key options:(SDImageCacheOptions)options done:(SDCacheQueryCompletedBlock)doneBlock { + return [self queryCacheOperationForKey:key options:options done:doneBlock context:nil]; +} + +- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock context:(nullable SDWebImageContext *)context { if (!key) { if (doneBlock) { doneBlock(nil, nil, SDImageCacheTypeNone); diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 3f88a41d..b1d18aa6 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -227,6 +227,28 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock; +/** + * Creates a SDWebImageDownloader async downloader instance with a given URL + * + * The delegate will be informed when the image is finish downloaded or an error has happen. + * + * @see SDWebImageDownloaderDelegate + * + * @param url The URL to the image to download + * @param options The options to be used for this download + * @param progressBlock A block called repeatedly while the image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called once the download is completed. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * + * @return A token (SDWebImageDownloadToken) that can be passed to -cancel: to cancel this operation + */ +- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url + options:(SDWebImageDownloaderOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock + context:(nullable SDWebImageContext *)context; + /** * Cancels a download that was previously queued using -downloadImageWithURL:options:progress:completed: * diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 12c66748..ec3837d0 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -174,10 +174,14 @@ } } +- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock { + return [self downloadImageWithURL:url options:options progress:progressBlock completed:completedBlock context:nil]; +} + - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock { + completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock context:(nullable SDWebImageContext *)context { __weak SDWebImageDownloader *wself = self; return [self addProgressCallback:progressBlock completedBlock:completedBlock forURL:url createCallback:^SDWebImageDownloaderOperation *{ @@ -203,6 +207,7 @@ } SDWebImageDownloaderOperation *operation = [[sself.operationClass alloc] initWithRequest:request inSession:sself.session options:options]; operation.shouldDecompressImages = sself.shouldDecompressImages; + operation.context = context; if (sself.urlCredential) { operation.credential = sself.urlCredential; diff --git a/SDWebImage/SDWebImageDownloaderOperation.h b/SDWebImage/SDWebImageDownloaderOperation.h index a21d02ea..32d116b0 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.h +++ b/SDWebImage/SDWebImageDownloaderOperation.h @@ -36,6 +36,9 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification - (nullable NSURLCredential *)credential; - (void)setCredential:(nullable NSURLCredential *)value; +- (nullable SDWebImageContext *)context; +- (void)setContext:(nullable SDWebImageContext *)context; + - (BOOL)cancel:(nullable id)token; @end @@ -67,19 +70,24 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification @property (nonatomic, strong, nullable) NSURLCredential *credential; /** - * The SDWebImageDownloaderOptions for the receiver. + * The options for the receiver. */ @property (assign, nonatomic, readonly) SDWebImageDownloaderOptions options; +/** + * The context for the receiver. + */ +@property (copy, nonatomic, nullable) SDWebImageContext *context; + /** * The expected size of data. */ -@property (assign, nonatomic) NSInteger expectedSize; +@property (assign, nonatomic, readonly) NSInteger expectedSize; /** * The response returned by the operation's connection. */ -@property (strong, nonatomic, nullable) NSURLResponse *response; +@property (strong, nonatomic, nullable, readonly) NSURLResponse *response; /** * Initializes a `SDWebImageDownloaderOperation` object diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index cffb1a86..252d0f21 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -29,6 +29,8 @@ typedef NSMutableDictionary SDCallbacksDictionary; @property (assign, nonatomic, getter = isFinished) BOOL finished; @property (strong, nonatomic, nullable) NSMutableData *imageData; @property (copy, nonatomic, nullable) NSData *cachedData; +@property (assign, nonatomic, readwrite) NSInteger expectedSize; +@property (strong, nonatomic, nullable, readwrite) NSURLResponse *response; // This is weak because it is injected by whoever manages this session. If this gets nil-ed out, we won't be able to run // the task associated with this operation diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 16bd05a2..42ee508f 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -241,6 +241,24 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nonnull SDInternalCompletionBlock)completedBlock; +/** + * Downloads the image at the given URL if not present in cache or return the cached version otherwise. + * + * @param url The URL to the image + * @param options A mask to specify options to use for this request + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * + * @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation + */ +- (nullable id )loadImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nonnull SDInternalCompletionBlock)completedBlock + context:(nullable SDWebImageContext *)context; + /** * Saves image to cache for given URL * diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 92b29826..90643930 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -107,10 +107,15 @@ }]; } -- (id )loadImageWithURL:(nullable NSURL *)url - options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nonnull SDInternalCompletionBlock)completedBlock { +- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDInternalCompletionBlock)completedBlock { + return [self loadImageWithURL:url options:options progress:progressBlock completed:completedBlock context:nil]; +} + +- (id)loadImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nonnull SDInternalCompletionBlock)completedBlock + context:(nullable SDWebImageContext *)context { // Invoking this method without a completedBlock is pointless NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead"); @@ -250,7 +255,7 @@ if (finished) { [self safelyRemoveOperationFromRunning:strongSubOperation]; } - }]; + } context:context]; } else if (cachedImage) { [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url]; [self safelyRemoveOperationFromRunning:strongOperation]; @@ -259,7 +264,7 @@ [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:nil data:nil error:nil cacheType:SDImageCacheTypeNone finished:YES url:url]; [self safelyRemoveOperationFromRunning:strongOperation]; } - }]; + } context:context]; return operation; } diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 613a5cd5..8461a65d 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -161,7 +161,7 @@ static char TAG_ACTIVITY_SHOW; callCompletedBlockClojure(); }); } - }]; + } context:context]; [self sd_setImageLoadOperation:operation forKey:validOperationKey]; } else { dispatch_main_async_safe(^{ From 1c0a13fb977cfaffe357bdd2062e63e2aabaa292 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 23 Jan 2018 21:37:58 +0800 Subject: [PATCH 023/361] Fix line-break --- SDWebImage/SDWebImageDownloader.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index ec3837d0..78ca83a1 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -181,7 +181,8 @@ - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock context:(nullable SDWebImageContext *)context { + completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock + context:(nullable SDWebImageContext *)context { __weak SDWebImageDownloader *wself = self; return [self addProgressCallback:progressBlock completedBlock:completedBlock forURL:url createCallback:^SDWebImageDownloaderOperation *{ From 5000e8095b7de713b6d6ba19d8894cf1caaa5154 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 26 Jan 2018 00:02:01 +0800 Subject: [PATCH 024/361] Fix the test for CustomDownloaderOperation --- Tests/Tests/SDWebImageDownloaderTests.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index fbc820ec..01bd978b 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -33,6 +33,7 @@ @property (nonatomic, assign) BOOL shouldDecompressImages; @property (nonatomic, strong, nullable) NSURLCredential *credential; +@property (nonatomic, assign) SDWebImageContext *context; @end From e012b36679ac4a664b04508218458b30a8c681d8 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 20 Jan 2018 23:40:16 +0800 Subject: [PATCH 025/361] Refactor the image indicator usage for UIView category. Use two protocol `SDWebImageIndicator` & `SDWebImageProgressIndicator` to make this more customizable. Implement two class about activity indicator and progress indicator for both UIKit/AppKit --- .../SDWebImage Demo/DetailViewController.m | 55 +---- .../SDWebImage Demo/MasterViewController.m | 4 +- Examples/SDWebImage OSX Demo/ViewController.m | 1 + SDWebImage.xcodeproj/project.pbxproj | 28 +++ SDWebImage/SDWebImageIndicator.h | 107 +++++++++ SDWebImage/SDWebImageIndicator.m | 224 ++++++++++++++++++ SDWebImage/UIView+WebCache.h | 24 +- SDWebImage/UIView+WebCache.m | 122 ++++------ WebImage/SDWebImage.h | 1 + 9 files changed, 425 insertions(+), 141 deletions(-) create mode 100644 SDWebImage/SDWebImageIndicator.h create mode 100644 SDWebImage/SDWebImageIndicator.m diff --git a/Examples/SDWebImage Demo/DetailViewController.m b/Examples/SDWebImage Demo/DetailViewController.m index 29656a5c..9e9d4540 100644 --- a/Examples/SDWebImage Demo/DetailViewController.m +++ b/Examples/SDWebImage Demo/DetailViewController.m @@ -7,64 +7,25 @@ */ #import "DetailViewController.h" -#import +#import #import @interface DetailViewController () @property (strong, nonatomic) IBOutlet FLAnimatedImageView *imageView; -@property (strong, nonatomic) UIActivityIndicatorView *activityIndicator; -@property (strong, nonatomic) UIProgressView *progressView; @end @implementation DetailViewController -- (UIActivityIndicatorView *)activityIndicator -{ - if (!_activityIndicator) { - _activityIndicator = [UIActivityIndicatorView.alloc initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; - _activityIndicator.center = self.imageView.center; - _activityIndicator.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; - [self.imageView addSubview:_activityIndicator]; - - } - return _activityIndicator; -} - -- (UIProgressView *)progressView -{ - if (!_progressView) { - _progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; - [self.view addSubview:_progressView]; - } - return _progressView; -} - - (void)configureView { - self.activityIndicator.hidden = NO; - [self.activityIndicator startAnimating]; - - __weak typeof(self) weakSelf = self; + if (!self.imageView.sd_imageIndicator) { + self.imageView.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator; + } [self.imageView sd_setImageWithURL:self.imageURL placeholderImage:nil - options:SDWebImageProgressiveDownload - progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL *targetURL) { - dispatch_async(dispatch_get_main_queue(), ^{ - float progress = 0; - if (expectedSize != 0) { - progress = (float)receivedSize / (float)expectedSize; - } - weakSelf.progressView.hidden = NO; - [weakSelf.progressView setProgress:progress animated:YES]; - }); - } - completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { - weakSelf.progressView.hidden = YES; - [weakSelf.activityIndicator stopAnimating]; - weakSelf.activityIndicator.hidden = YES; - }]; + options:SDWebImageProgressiveDownload]; } - (void)viewDidLoad @@ -73,12 +34,6 @@ [self configureView]; } -- (void)viewDidLayoutSubviews -{ - [super viewDidLayoutSubviews]; - self.progressView.frame = CGRectMake(0, self.topLayoutGuide.length, CGRectGetWidth(self.view.bounds), 2.0); -} - - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); diff --git a/Examples/SDWebImage Demo/MasterViewController.m b/Examples/SDWebImage Demo/MasterViewController.m index 5e2b37bb..3758959f 100644 --- a/Examples/SDWebImage Demo/MasterViewController.m +++ b/Examples/SDWebImage Demo/MasterViewController.m @@ -118,10 +118,8 @@ if (cell == nil) { cell = [[MyCustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; cell.customImageView.sd_imageTransition = SDWebImageTransition.fadeTransition; + cell.customImageView.sd_imageIndicator = SDWebImageActivityIndicator.grayIndicator; } - - [cell.customImageView sd_setShowActivityIndicatorView:YES]; - [cell.customImageView sd_setIndicatorStyle:UIActivityIndicatorViewStyleGray]; cell.customTextLabel.text = [NSString stringWithFormat:@"Image #%ld", (long)indexPath.row]; [cell.customImageView sd_setImageWithURL:[NSURL URLWithString:self.objects[indexPath.row]] diff --git a/Examples/SDWebImage OSX Demo/ViewController.m b/Examples/SDWebImage OSX Demo/ViewController.m index ad534b77..3575d448 100644 --- a/Examples/SDWebImage OSX Demo/ViewController.m +++ b/Examples/SDWebImage OSX Demo/ViewController.m @@ -31,6 +31,7 @@ // For animated GIF rendering, set `animates` to YES or will only show the first frame self.imageView1.animates = YES; self.imageView3.animates = YES; + self.imageView1.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator; [self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"http://assets.sbnation.com/assets/2512203/dogflops.gif"]]; [self.imageView2 sd_setImageWithURL:[NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp"]]; [self.imageView3 sd_setImageWithURL:[NSURL URLWithString:@"http://littlesvr.ca/apng/images/SteamEngine.webp"]]; diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 33182a00..8ef67fec 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -362,6 +362,18 @@ 329A18621FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; 329A18631FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; 329A18641FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; + 32C0FDE12013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32C0FDE22013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32C0FDE32013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32C0FDE42013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32C0FDE52013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32C0FDE62013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32C0FDE72013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; + 32C0FDE82013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; + 32C0FDE92013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; + 32C0FDEA2013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; + 32C0FDEB2013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; + 32C0FDEC2013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; 32CF1C071FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32CF1C081FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32CF1C091FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1371,6 +1383,8 @@ 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageFrame.m; sourceTree = ""; }; 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImage+WebCache.h"; path = "SDWebImage/UIImage+WebCache.h"; sourceTree = ""; }; 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImage+WebCache.m"; path = "SDWebImage/UIImage+WebCache.m"; sourceTree = ""; }; + 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageIndicator.h; sourceTree = ""; }; + 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageIndicator.m; sourceTree = ""; }; 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoderHelper.h; sourceTree = ""; }; 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCoderHelper.m; sourceTree = ""; }; 4314D1991D0E0E3B004B36C9 /* libSDWebImage watchOS static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libSDWebImage watchOS static.a"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1856,6 +1870,8 @@ 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */, 325312C6200F09910046BF1E /* SDWebImageTransition.h */, 325312C7200F09910046BF1E /* SDWebImageTransition.m */, + 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */, + 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */, ); name = Utils; sourceTree = ""; @@ -2105,6 +2121,7 @@ 323F8BF91F38EF770092B609 /* animi.h in Headers */, 80377C4F1F2F666300F89830 /* filters_utils.h in Headers */, 80377C4C1F2F666300F89830 /* color_cache_utils.h in Headers */, + 32C0FDE42013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 321E60C11F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 80377DBE1F2F66A700F89830 /* dsp.h in Headers */, 80377EB81F2F66D400F89830 /* alphai_dec.h in Headers */, @@ -2163,6 +2180,7 @@ 80377C1B1F2F666300F89830 /* filters_utils.h in Headers */, 323F8B6F1F38EF770092B609 /* delta_palettization_enc.h in Headers */, 4314D1781D0E0E3B004B36C9 /* SDWebImageDownloader.h in Headers */, + 32C0FDE22013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 80377E981F2F66D400F89830 /* alphai_dec.h in Headers */, 4314D1791D0E0E3B004B36C9 /* SDWebImageManager.h in Headers */, 323F8BE51F38EF770092B609 /* vp8li_enc.h in Headers */, @@ -2243,6 +2261,7 @@ 80377C671F2F666400F89830 /* endian_inl_utils.h in Headers */, 80377C6B1F2F666400F89830 /* huffman_encode_utils.h in Headers */, 323F8C121F38EF770092B609 /* muxi.h in Headers */, + 32C0FDE52013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 80377ED61F2F66D500F89830 /* webpi_dec.h in Headers */, 323F8BE81F38EF770092B609 /* vp8li_enc.h in Headers */, 323F8B8A1F38EF770092B609 /* histogram_enc.h in Headers */, @@ -2326,6 +2345,7 @@ 80377E3A1F2F66A800F89830 /* common_sse2.h in Headers */, 4397D2D91D0DDD8C00BB2784 /* SDWebImagePrefetcher.h in Headers */, 80377C871F2F666400F89830 /* huffman_utils.h in Headers */, + 32C0FDE62013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 4397D2DA1D0DDD8C00BB2784 /* UIView+WebCacheOperation.h in Headers */, 80377E661F2F66A800F89830 /* neon.h in Headers */, 4397D2DB1D0DDD8C00BB2784 /* UIImage+MultiFormat.h in Headers */, @@ -2427,6 +2447,7 @@ 80377C351F2F666300F89830 /* filters_utils.h in Headers */, 80377C321F2F666300F89830 /* color_cache_utils.h in Headers */, 321E60C01F38E91700405457 /* UIImage+ForceDecode.h in Headers */, + 32C0FDE32013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 80377D791F2F66A700F89830 /* dsp.h in Headers */, 80377EA81F2F66D400F89830 /* alphai_dec.h in Headers */, 4A2CAE2D1AB4BB7500B6BC39 /* UIImage+GIF.h in Headers */, @@ -2449,6 +2470,7 @@ 53761316155AD0D5005750A4 /* SDImageCache.h in Headers */, 323F8C0E1F38EF770092B609 /* muxi.h in Headers */, 325312C8200F09910046BF1E /* SDWebImageTransition.h in Headers */, + 32C0FDE12013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 321E60A21F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, 5D5B9142188EE8DD006D06BD /* NSData+ImageContentType.h in Headers */, 80377BFE1F2F665300F89830 /* color_cache_utils.h in Headers */, @@ -2779,6 +2801,7 @@ 321E60B91F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 80377DEB1F2F66A700F89830 /* yuv.c in Sources */, 3237F9E920161AE000A88143 /* NSImage+Additions.m in Sources */, + 32C0FDEA2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 00733A551BC4880000A5A117 /* SDWebImageDownloader.m in Sources */, 80377EB71F2F66D400F89830 /* alpha_dec.c in Sources */, 80377DC61F2F66A700F89830 /* enc.c in Sources */, @@ -2980,6 +3003,7 @@ 323F8BA91F38EF770092B609 /* picture_psnr_enc.c in Sources */, 323F8C091F38EF770092B609 /* muxedit.c in Sources */, 80377D1F1F2F66A700F89830 /* alpha_processing_neon.c in Sources */, + 32C0FDE82013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 4314D1401D0E0E3B004B36C9 /* UIImageView+WebCache.m in Sources */, 43A9186C1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, 3237F9EC20161AE000A88143 /* NSImage+Additions.m in Sources */, @@ -3127,6 +3151,7 @@ 80377C611F2F666400F89830 /* bit_reader_utils.c in Sources */, 323F8BAC1F38EF770092B609 /* picture_psnr_enc.c in Sources */, 323F8C0C1F38EF770092B609 /* muxedit.c in Sources */, + 32C0FDEB2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 80377DEE1F2F66A800F89830 /* alpha_processing_neon.c in Sources */, 43C892A41D9D6DDD0022038D /* demux.c in Sources */, 3237F9EA20161AE000A88143 /* NSImage+Additions.m in Sources */, @@ -3312,6 +3337,7 @@ 4369C2831D9807EC007E863A /* UIView+WebCache.m in Sources */, 80377E611F2F66A800F89830 /* lossless_sse2.c in Sources */, 80377E691F2F66A800F89830 /* rescaler_msa.c in Sources */, + 32C0FDEC2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 80377E5E1F2F66A800F89830 /* lossless_mips_dsp_r2.c in Sources */, 80377E3D1F2F66A800F89830 /* cost_sse2.c in Sources */, 321E60BB1F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, @@ -3373,6 +3399,7 @@ 321E60B81F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 43CE757A1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, 3237F9E820161AE000A88143 /* NSImage+Additions.m in Sources */, + 32C0FDE92013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 80377D811F2F66A700F89830 /* enc.c in Sources */, 80377EA71F2F66D400F89830 /* alpha_dec.c in Sources */, 80377D8F1F2F66A700F89830 /* lossless_mips_dsp_r2.c in Sources */, @@ -3524,6 +3551,7 @@ 43CE75791CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, 80377CF71F2F66A100F89830 /* enc.c in Sources */, 3237F9EB20161AE000A88143 /* NSImage+Additions.m in Sources */, + 32C0FDE72013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 80377E871F2F66D000F89830 /* alpha_dec.c in Sources */, 80377D051F2F66A100F89830 /* lossless_mips_dsp_r2.c in Sources */, 80377C0A1F2F665300F89830 /* random_utils.c in Sources */, diff --git a/SDWebImage/SDWebImageIndicator.h b/SDWebImage/SDWebImageIndicator.h new file mode 100644 index 00000000..5fe03bae --- /dev/null +++ b/SDWebImage/SDWebImageIndicator.h @@ -0,0 +1,107 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +#if SD_UIKIT || SD_MAC + +// A protocol to custom the indicator during the image loading +// All of these methods are called from main queue +@protocol SDWebImageIndicator + +@required +/** + The view associate to the indicator. + + @return The indicator view + */ +- (nonnull UIView *)indicatorView; +/** + Start the animating for indicator. + */ +- (void)startAnimatingIndicator; +/** + Stop the animating for indicator. + */ +- (void)stopAnimatingIndicator; + +@end + +// A protocol to custom the indicator which need update when loading progress changed +// All of these methods are called from main queue +@protocol SDWebImageProgressIndicator + +@required +/** + Update the progress (0-1.0) for progress indicator. + + @param progress The progress, value between 0 and 1.0 + */ +- (void)updateProgress:(double)progress; + +@end + +#pragma mark - Activity Indicator + +// Activity indicator class +// for UIKit(macOS), it use a `UIActivityIndicatorView` +// for AppKit(macOS), it use a `NSProgressIndicator` with the spinning style +@interface SDWebImageActivityIndicator : NSObject + +#if SD_UIKIT +@property (nonatomic, strong, readonly, nonnull) UIActivityIndicatorView *indicatorView; +#else +@property (nonatomic, strong, readonly, nonnull) NSProgressIndicator *indicatorView; +#endif + +@end + +// Convenience way to use activity indicator. +@interface SDWebImageActivityIndicator (Conveniences) + +/// gray-style activity indicator +@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *grayIndicator __TVOS_UNAVAILABLE; +/// large gray-style activity indicator +@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *grayLargeIndicator NS_AVAILABLE_MAC(10_2); +/// white-style activity indicator +@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *whiteIndicator; +/// large white-style activity indicator +@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *whiteLargeIndicator; + +@end + +#pragma mark - Progress Indicator + +// Progress indicator class +// for UIKit(macOS), it use a `UIProgressView` +// for AppKit(macOS), it use a `NSProgressIndicator` with the bar style +@interface SDWebImageProgressIndicator : NSObject + +#if SD_UIKIT +@property (nonatomic, strong, readonly, nonnull) UIProgressView *indicatorView; +#else +@property (nonatomic, strong, readonly, nonnull) NSProgressIndicator *indicatorView; +#endif +/** + The preferred width for progress indicator. The getter and setter just pass to the indicatorView's frame. The default value is `UIProgressView`'s natural width. + */ +@property (nonatomic, assign) CGFloat indicatorWidth; + +@end + +// Convenience way to use progress indicator. Remember to set the indicatorWidth +@interface SDWebImageProgressIndicator (Conveniences) + +/// default-style progress indicator +@property (nonatomic, class, nonnull, readonly) SDWebImageProgressIndicator *defaultIndicator; +/// bar-style progress indicator +@property (nonatomic, class, nonnull, readonly) SDWebImageProgressIndicator *barIndicator NS_AVAILABLE_IOS(2_0) __TVOS_UNAVAILABLE; + +@end + +#endif diff --git a/SDWebImage/SDWebImageIndicator.m b/SDWebImage/SDWebImageIndicator.m new file mode 100644 index 00000000..81115228 --- /dev/null +++ b/SDWebImage/SDWebImageIndicator.m @@ -0,0 +1,224 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageIndicator.h" + +#if SD_UIKIT || SD_MAC + +#if SD_MAC +#import +#endif + +#pragma mark - Activity Indicator + +@interface SDWebImageActivityIndicator () + +#if SD_UIKIT +@property (nonatomic, strong, readwrite, nonnull) UIActivityIndicatorView *indicatorView; +#else +@property (nonatomic, strong, readwrite, nonnull) NSProgressIndicator *indicatorView; +#endif + +@end + +@implementation SDWebImageActivityIndicator + +- (instancetype)init { + self = [super init]; + if (self) { + [self commonInit]; + } + return self; +} + +#if SD_UIKIT +- (void)commonInit { +#if SD_TV + UIActivityIndicatorViewStyle style = UIActivityIndicatorViewStyleWhite; +#else + UIActivityIndicatorViewStyle style = UIActivityIndicatorViewStyleGray; +#endif + self.indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:style]; + self.indicatorView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin; +} +#endif + +#if SD_MAC +- (void)commonInit { + self.indicatorView = [[NSProgressIndicator alloc] initWithFrame:NSZeroRect]; + self.indicatorView.style = NSProgressIndicatorStyleSpinning; + self.indicatorView.controlSize = NSControlSizeSmall; + [self.indicatorView sizeToFit]; + self.indicatorView.autoresizingMask = NSViewMaxXMargin | NSViewMinXMargin | NSViewMaxYMargin | NSViewMinYMargin; +} +#endif + +- (void)startAnimatingIndicator { +#if SD_UIKIT + [self.indicatorView startAnimating]; +#else + [self.indicatorView startAnimation:nil]; +#endif + self.indicatorView.hidden = NO; +} + +- (void)stopAnimatingIndicator { +#if SD_UIKIT + [self.indicatorView stopAnimating]; +#else + [self.indicatorView stopAnimation:nil]; +#endif + self.indicatorView.hidden = YES; +} + +@end + +@implementation SDWebImageActivityIndicator (Conveniences) + +#if SD_MAC || SD_IOS ++ (SDWebImageActivityIndicator *)grayIndicator { + SDWebImageActivityIndicator *indicator = [SDWebImageActivityIndicator new]; + return indicator; +} +#endif + +#if SD_MAC ++ (SDWebImageActivityIndicator *)grayLargeIndicator { + SDWebImageActivityIndicator *indicator = SDWebImageActivityIndicator.grayIndicator; + indicator.indicatorView.controlSize = NSControlSizeRegular; + [indicator.indicatorView sizeToFit]; + return indicator; +} +#endif + ++ (SDWebImageActivityIndicator *)whiteIndicator { + SDWebImageActivityIndicator *indicator = [SDWebImageActivityIndicator new]; +#if SD_UIKIT + indicator.indicatorView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhite; +#else + CIFilter *lighten = [CIFilter filterWithName:@"CIColorControls"]; + [lighten setDefaults]; + [lighten setValue:@(1) forKey:kCIInputBrightnessKey]; + indicator.indicatorView.contentFilters = @[lighten]; +#endif + return indicator; +} + ++ (SDWebImageActivityIndicator *)whiteLargeIndicator { + SDWebImageActivityIndicator *indicator = SDWebImageActivityIndicator.whiteIndicator; +#if SD_UIKIT + indicator.indicatorView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge; +#else + indicator.indicatorView.controlSize = NSControlSizeRegular; + [indicator.indicatorView sizeToFit]; +#endif + return indicator; +} + +@end + +#pragma mark - Progress Indicator + +@interface SDWebImageProgressIndicator () + +#if SD_UIKIT +@property (nonatomic, strong, readwrite, nonnull) UIProgressView *indicatorView; +#else +@property (nonatomic, strong, readwrite, nonnull) NSProgressIndicator *indicatorView; +#endif + +@end + +@implementation SDWebImageProgressIndicator + +- (instancetype)init { + self = [super init]; + if (self) { + [self commonInit]; + } + return self; +} + +#if SD_UIKIT +- (void)commonInit { + self.indicatorView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; + self.indicatorView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin; +} +#endif + +#if SD_MAC +- (void)commonInit { + self.indicatorView = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0, 0, 160, 0)]; + self.indicatorView.style = NSProgressIndicatorStyleBar; + self.indicatorView.controlSize = NSControlSizeSmall; + [self.indicatorView sizeToFit]; + self.indicatorView.autoresizingMask = NSViewMaxXMargin | NSViewMinXMargin | NSViewMaxYMargin | NSViewMinYMargin; +} +#endif + +- (CGFloat)indicatorWidth { + return self.indicatorView.frame.size.width; +} + +- (void)setIndicatorWidth:(CGFloat)indicatorWidth { + CGRect frame = self.indicatorView.frame; + frame.size.width = indicatorWidth; + self.indicatorView.frame = frame; +} + +- (void)startAnimatingIndicator { + self.indicatorView.hidden = NO; +#if SD_UIKIT + self.indicatorView.progress = 0; +#else + self.indicatorView.indeterminate = YES; + self.indicatorView.doubleValue = 0; + [self.indicatorView startAnimation:nil]; +#endif +} + +- (void)stopAnimatingIndicator { + self.indicatorView.hidden = YES; +#if SD_UIKIT + self.indicatorView.progress = 1; +#else + self.indicatorView.indeterminate = NO; + self.indicatorView.doubleValue = 1; + [self.indicatorView stopAnimation:nil]; +#endif +} + +- (void)updateProgress:(double)progress { +#if SD_UIKIT + [self.indicatorView setProgress:progress animated:YES]; +#else + self.indicatorView.indeterminate = progress > 0 ? NO : YES; + self.indicatorView.doubleValue = progress * 100; +#endif +} + +@end + +@implementation SDWebImageProgressIndicator (Conveniences) + ++ (SDWebImageProgressIndicator *)defaultIndicator { + SDWebImageProgressIndicator *indicator = [SDWebImageProgressIndicator new]; + return indicator; +} + +#if SD_IOS ++ (SDWebImageProgressIndicator *)barIndicator { + SDWebImageProgressIndicator *indicator = [SDWebImageProgressIndicator new]; + indicator.indicatorView.progressViewStyle = UIProgressViewStyleBar; + return indicator; +} +#endif + +@end + +#endif diff --git a/SDWebImage/UIView+WebCache.h b/SDWebImage/UIView+WebCache.h index 37c39f35..593e6be3 100644 --- a/SDWebImage/UIView+WebCache.h +++ b/SDWebImage/UIView+WebCache.h @@ -13,6 +13,7 @@ #import "SDWebImageDefine.h" #import "SDWebImageManager.h" #import "SDWebImageTransition.h" +#import "SDWebImageIndicator.h" /** The value specify that the image progress unit count cannot be determined because the progressBlock is not been called. @@ -106,27 +107,14 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima */ @property (nonatomic, strong, nullable) SDWebImageTransition *sd_imageTransition; -#if SD_UIKIT - -#pragma mark - Activity indicator +#pragma mark - Image Indicator /** - * Show activity UIActivityIndicatorView + The image indicator during the image loading. If you do not need indicator, specify nil. Defaults to nil + The setter will remove the old indicator view and add new indicator view to current view's subview. + @note Because this is UI related, you should access only from the main queue. */ -- (void)sd_setShowActivityIndicatorView:(BOOL)show; - -/** - * set desired UIActivityIndicatorViewStyle - * - * @param style The style of the UIActivityIndicatorView - */ -- (void)sd_setIndicatorStyle:(UIActivityIndicatorViewStyle)style; - -- (BOOL)sd_showActivityIndicatorView; -- (void)sd_addActivityIndicator; -- (void)sd_removeActivityIndicator; - -#endif +@property (nonatomic, strong, nullable) id sd_imageIndicator; @end diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 182917f4..9c43b3d1 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -17,12 +17,6 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; static char imageURLKey; -#if SD_UIKIT -static char TAG_ACTIVITY_INDICATOR; -static char TAG_ACTIVITY_STYLE; -#endif -static char TAG_ACTIVITY_SHOW; - @implementation UIView (WebCache) - (nullable NSURL *)sd_imageURL { @@ -79,10 +73,8 @@ static char TAG_ACTIVITY_SHOW; } if (url) { - // check if activityView is enabled or not - if ([self sd_showActivityIndicatorView]) { - [self sd_addActivityIndicator]; - } + // check and start image indicator + [self sd_startImageIndicator]; // reset the progress self.sd_imageProgress.totalUnitCount = 0; @@ -95,6 +87,8 @@ static char TAG_ACTIVITY_SHOW; manager = [SDWebImageManager sharedManager]; } + id imageIndicator = self.sd_imageIndicator; + __weak __typeof(self)wself = self; SDWebImageDownloaderProgressBlock combinedProgressBlock = ^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { wself.sd_imageProgress.totalUnitCount = expectedSize; @@ -102,11 +96,20 @@ static char TAG_ACTIVITY_SHOW; if (progressBlock) { progressBlock(receivedSize, expectedSize, targetURL); } + if ([imageIndicator conformsToProtocol:@protocol(SDWebImageProgressIndicator)]) { + double progress = wself.sd_imageProgress.fractionCompleted; + dispatch_async(dispatch_get_main_queue(), ^{ + [((id)imageIndicator) updateProgress:progress]; + }); + } }; id operation = [manager loadImageWithURL:url options:options progress:combinedProgressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { __strong __typeof (wself) sself = wself; if (!sself) { return; } - [sself sd_removeActivityIndicator]; + // check and stop image indicator + if (finished) { + [self sd_stopImageIndicator]; + } // if the progress not been updated, mark it to complete state if (finished && !error && sself.sd_imageProgress.totalUnitCount == 0 && sself.sd_imageProgress.completedUnitCount == 0) { sself.sd_imageProgress.totalUnitCount = SDWebImageProgressUnitCountUnknown; @@ -170,8 +173,8 @@ static char TAG_ACTIVITY_SHOW; } context:context]; [self sd_setImageLoadOperation:operation forKey:validOperationKey]; } else { + [self sd_stopImageIndicator]; dispatch_main_async_safe(^{ - [self sd_removeActivityIndicator]; if (completedBlock) { NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; completedBlock(nil, error, SDImageCacheTypeNone, url); @@ -277,75 +280,54 @@ static char TAG_ACTIVITY_SHOW; objc_setAssociatedObject(self, @selector(sd_imageTransition), sd_imageTransition, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -#pragma mark - Activity indicator - -#pragma mark - -#if SD_UIKIT -- (UIActivityIndicatorView *)activityIndicator { - return (UIActivityIndicatorView *)objc_getAssociatedObject(self, &TAG_ACTIVITY_INDICATOR); +#pragma mark - Indicator +- (id)sd_imageIndicator { + return objc_getAssociatedObject(self, @selector(sd_imageIndicator)); } -- (void)setActivityIndicator:(UIActivityIndicatorView *)activityIndicator { - objc_setAssociatedObject(self, &TAG_ACTIVITY_INDICATOR, activityIndicator, OBJC_ASSOCIATION_RETAIN); -} +- (void)setSd_imageIndicator:(id)sd_imageIndicator { + id previousIndicator = self.sd_imageIndicator; + if (previousIndicator == sd_imageIndicator) { + [previousIndicator.indicatorView removeFromSuperview]; + } + + // Add the new indicator view + UIView *view = sd_imageIndicator.indicatorView; + if (CGRectEqualToRect(view.frame, CGRectZero)) { + view.frame = self.frame; + } + // Center the indicator view +#if SD_MAC + CGPoint center = CGPointMake(NSMidX(self.bounds), NSMidY(self.bounds)); + NSRect frame = view.frame; + view.frame = NSMakeRect(center.x - NSMidX(frame), center.y - NSMidY(frame), NSWidth(frame), NSHeight(frame)); +#else + view.center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)); #endif - -- (void)sd_setShowActivityIndicatorView:(BOOL)show { - objc_setAssociatedObject(self, &TAG_ACTIVITY_SHOW, @(show), OBJC_ASSOCIATION_RETAIN); + view.hidden = NO; + [self addSubview:view]; + + objc_setAssociatedObject(self, @selector(sd_imageIndicator), sd_imageIndicator, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -- (BOOL)sd_showActivityIndicatorView { - return [objc_getAssociatedObject(self, &TAG_ACTIVITY_SHOW) boolValue]; -} - -#if SD_UIKIT -- (void)sd_setIndicatorStyle:(UIActivityIndicatorViewStyle)style{ - objc_setAssociatedObject(self, &TAG_ACTIVITY_STYLE, [NSNumber numberWithInt:style], OBJC_ASSOCIATION_RETAIN); -} - -- (int)sd_getIndicatorStyle{ - return [objc_getAssociatedObject(self, &TAG_ACTIVITY_STYLE) intValue]; -} -#endif - -- (void)sd_addActivityIndicator { -#if SD_UIKIT +- (void)sd_startImageIndicator { + id imageIndicator = self.sd_imageIndicator; + if (!imageIndicator) { + return; + } dispatch_main_async_safe(^{ - if (!self.activityIndicator) { - self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:[self sd_getIndicatorStyle]]; - self.activityIndicator.translatesAutoresizingMaskIntoConstraints = NO; - - [self addSubview:self.activityIndicator]; - - [self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator - attribute:NSLayoutAttributeCenterX - relatedBy:NSLayoutRelationEqual - toItem:self - attribute:NSLayoutAttributeCenterX - multiplier:1.0 - constant:0.0]]; - [self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator - attribute:NSLayoutAttributeCenterY - relatedBy:NSLayoutRelationEqual - toItem:self - attribute:NSLayoutAttributeCenterY - multiplier:1.0 - constant:0.0]]; - } - [self.activityIndicator startAnimating]; + [imageIndicator startAnimatingIndicator]; }); -#endif } -- (void)sd_removeActivityIndicator { -#if SD_UIKIT +- (void)sd_stopImageIndicator { + id imageIndicator = self.sd_imageIndicator; + if (!imageIndicator) { + return; + } dispatch_main_async_safe(^{ - if (self.activityIndicator) { - [self.activityIndicator removeFromSuperview]; - self.activityIndicator = nil; - } + [imageIndicator stopAnimatingIndicator]; }); -#endif } @end diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index b899118e..0ec05265 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -36,6 +36,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import +#import #if SD_MAC || SD_UIKIT #import From 1ebac224db47e2202d2cd37e82d9c1a0e428a573 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 21 Jan 2018 11:54:41 +0800 Subject: [PATCH 026/361] Use the API_UNAVAILABLE macro from Xcode 8 instead of the old style --- SDWebImage/SDWebImageIndicator.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SDWebImage/SDWebImageIndicator.h b/SDWebImage/SDWebImageIndicator.h index 5fe03bae..845d3e6f 100644 --- a/SDWebImage/SDWebImageIndicator.h +++ b/SDWebImage/SDWebImageIndicator.h @@ -65,9 +65,9 @@ @interface SDWebImageActivityIndicator (Conveniences) /// gray-style activity indicator -@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *grayIndicator __TVOS_UNAVAILABLE; +@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *grayIndicator API_UNAVAILABLE(tvos); /// large gray-style activity indicator -@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *grayLargeIndicator NS_AVAILABLE_MAC(10_2); +@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *grayLargeIndicator API_UNAVAILABLE(ios, tvos); /// white-style activity indicator @property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *whiteIndicator; /// large white-style activity indicator @@ -100,7 +100,7 @@ /// default-style progress indicator @property (nonatomic, class, nonnull, readonly) SDWebImageProgressIndicator *defaultIndicator; /// bar-style progress indicator -@property (nonatomic, class, nonnull, readonly) SDWebImageProgressIndicator *barIndicator NS_AVAILABLE_IOS(2_0) __TVOS_UNAVAILABLE; +@property (nonatomic, class, nonnull, readonly) SDWebImageProgressIndicator *barIndicator API_UNAVAILABLE(macos, tvos); @end From 529f6fe4bfb18d2782bd3992feb7e1c88b026a3d Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 4 Feb 2018 15:08:33 +0800 Subject: [PATCH 027/361] Rename to updateIndicatorProgress. Change the order for progress update and indicator to allow `observedProgress` works. --- SDWebImage/SDWebImageIndicator.h | 2 +- SDWebImage/SDWebImageIndicator.m | 20 ++++++++++++++++---- SDWebImage/UIView+WebCache.m | 18 ++++++++++-------- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/SDWebImage/SDWebImageIndicator.h b/SDWebImage/SDWebImageIndicator.h index 845d3e6f..4078ab95 100644 --- a/SDWebImage/SDWebImageIndicator.h +++ b/SDWebImage/SDWebImageIndicator.h @@ -42,7 +42,7 @@ @param progress The progress, value between 0 and 1.0 */ -- (void)updateProgress:(double)progress; +- (void)updateIndicatorProgress:(double)progress; @end diff --git a/SDWebImage/SDWebImageIndicator.m b/SDWebImage/SDWebImageIndicator.m index 81115228..9aa06b56 100644 --- a/SDWebImage/SDWebImageIndicator.m +++ b/SDWebImage/SDWebImageIndicator.m @@ -174,7 +174,11 @@ - (void)startAnimatingIndicator { self.indicatorView.hidden = NO; #if SD_UIKIT - self.indicatorView.progress = 0; + if ([self.indicatorView respondsToSelector:@selector(observedProgress)] && self.indicatorView.observedProgress) { + // Ignore NSProgress + } else { + self.indicatorView.progress = 0; + } #else self.indicatorView.indeterminate = YES; self.indicatorView.doubleValue = 0; @@ -185,7 +189,11 @@ - (void)stopAnimatingIndicator { self.indicatorView.hidden = YES; #if SD_UIKIT - self.indicatorView.progress = 1; + if ([self.indicatorView respondsToSelector:@selector(observedProgress)] && self.indicatorView.observedProgress) { + // Ignore NSProgress + } else { + self.indicatorView.progress = 1; + } #else self.indicatorView.indeterminate = NO; self.indicatorView.doubleValue = 1; @@ -193,9 +201,13 @@ #endif } -- (void)updateProgress:(double)progress { +- (void)updateIndicatorProgress:(double)progress { #if SD_UIKIT - [self.indicatorView setProgress:progress animated:YES]; + if ([self.indicatorView respondsToSelector:@selector(observedProgress)] && self.indicatorView.observedProgress) { + // Ignore NSProgress + } else { + [self.indicatorView setProgress:progress animated:YES]; + } #else self.indicatorView.indeterminate = progress > 0 ? NO : YES; self.indicatorView.doubleValue = progress * 100; diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 9c43b3d1..f929d7ff 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -73,13 +73,13 @@ static char imageURLKey; } if (url) { - // check and start image indicator - [self sd_startImageIndicator]; - // reset the progress self.sd_imageProgress.totalUnitCount = 0; self.sd_imageProgress.completedUnitCount = 0; + // check and start image indicator + [self sd_startImageIndicator]; + SDWebImageManager *manager; if ([context valueForKey:SDWebImageContextCustomManager]) { manager = (SDWebImageManager *)[context valueForKey:SDWebImageContextCustomManager]; @@ -99,22 +99,24 @@ static char imageURLKey; if ([imageIndicator conformsToProtocol:@protocol(SDWebImageProgressIndicator)]) { double progress = wself.sd_imageProgress.fractionCompleted; dispatch_async(dispatch_get_main_queue(), ^{ - [((id)imageIndicator) updateProgress:progress]; + [((id)imageIndicator) updateIndicatorProgress:progress]; }); } }; id operation = [manager loadImageWithURL:url options:options progress:combinedProgressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { __strong __typeof (wself) sself = wself; if (!sself) { return; } - // check and stop image indicator - if (finished) { - [self sd_stopImageIndicator]; - } // if the progress not been updated, mark it to complete state if (finished && !error && sself.sd_imageProgress.totalUnitCount == 0 && sself.sd_imageProgress.completedUnitCount == 0) { sself.sd_imageProgress.totalUnitCount = SDWebImageProgressUnitCountUnknown; sself.sd_imageProgress.completedUnitCount = SDWebImageProgressUnitCountUnknown; } + + // check and stop image indicator + if (finished) { + [self sd_stopImageIndicator]; + } + BOOL shouldCallCompletedBlock = finished || (options & SDWebImageAvoidAutoSetImage); BOOL shouldNotSetImage = ((image && (options & SDWebImageAvoidAutoSetImage)) || (!image && !(options & SDWebImageDelayPlaceholder))); From d28870cd5202ce54eb4508e16decfb709a7d0ca3 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 4 Feb 2018 15:11:35 +0800 Subject: [PATCH 028/361] Remove the indicatorWidth property. Use can use the indicatorView to directly modify the frame or constraint --- SDWebImage/SDWebImageIndicator.h | 6 +----- SDWebImage/SDWebImageIndicator.m | 10 ---------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/SDWebImage/SDWebImageIndicator.h b/SDWebImage/SDWebImageIndicator.h index 4078ab95..df1cf969 100644 --- a/SDWebImage/SDWebImageIndicator.h +++ b/SDWebImage/SDWebImageIndicator.h @@ -87,14 +87,10 @@ #else @property (nonatomic, strong, readonly, nonnull) NSProgressIndicator *indicatorView; #endif -/** - The preferred width for progress indicator. The getter and setter just pass to the indicatorView's frame. The default value is `UIProgressView`'s natural width. - */ -@property (nonatomic, assign) CGFloat indicatorWidth; @end -// Convenience way to use progress indicator. Remember to set the indicatorWidth +// Convenience way to create progress indicator. Remember to specify the indicator width or use layout constraint if need. @interface SDWebImageProgressIndicator (Conveniences) /// default-style progress indicator diff --git a/SDWebImage/SDWebImageIndicator.m b/SDWebImage/SDWebImageIndicator.m index 9aa06b56..ba34e61f 100644 --- a/SDWebImage/SDWebImageIndicator.m +++ b/SDWebImage/SDWebImageIndicator.m @@ -161,16 +161,6 @@ } #endif -- (CGFloat)indicatorWidth { - return self.indicatorView.frame.size.width; -} - -- (void)setIndicatorWidth:(CGFloat)indicatorWidth { - CGRect frame = self.indicatorView.frame; - frame.size.width = indicatorWidth; - self.indicatorView.frame = frame; -} - - (void)startAnimatingIndicator { self.indicatorView.hidden = NO; #if SD_UIKIT From 89babbbfbe09fda697b566624c31162380dfe884 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 4 Feb 2018 15:19:40 +0800 Subject: [PATCH 029/361] Remove SDWebImageProgressIndicator protocol. Add this as an optional method in SDWebImageIndicator --- SDWebImage/SDWebImageIndicator.h | 14 ++++---------- SDWebImage/UIView+WebCache.m | 4 ++-- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/SDWebImage/SDWebImageIndicator.h b/SDWebImage/SDWebImageIndicator.h index df1cf969..f6ab96f6 100644 --- a/SDWebImage/SDWebImageIndicator.h +++ b/SDWebImage/SDWebImageIndicator.h @@ -30,16 +30,10 @@ */ - (void)stopAnimatingIndicator; -@end - -// A protocol to custom the indicator which need update when loading progress changed -// All of these methods are called from main queue -@protocol SDWebImageProgressIndicator - -@required +@optional /** - Update the progress (0-1.0) for progress indicator. - + Update the loading progress (0-1.0) for indicator. Optional + @param progress The progress, value between 0 and 1.0 */ - (void)updateIndicatorProgress:(double)progress; @@ -80,7 +74,7 @@ // Progress indicator class // for UIKit(macOS), it use a `UIProgressView` // for AppKit(macOS), it use a `NSProgressIndicator` with the bar style -@interface SDWebImageProgressIndicator : NSObject +@interface SDWebImageProgressIndicator : NSObject #if SD_UIKIT @property (nonatomic, strong, readonly, nonnull) UIProgressView *indicatorView; diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index f929d7ff..3ab40e82 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -96,10 +96,10 @@ static char imageURLKey; if (progressBlock) { progressBlock(receivedSize, expectedSize, targetURL); } - if ([imageIndicator conformsToProtocol:@protocol(SDWebImageProgressIndicator)]) { + if ([imageIndicator respondsToSelector:@selector(updateIndicatorProgress:)]) { double progress = wself.sd_imageProgress.fractionCompleted; dispatch_async(dispatch_get_main_queue(), ^{ - [((id)imageIndicator) updateIndicatorProgress:progress]; + [imageIndicator updateIndicatorProgress:progress]; }); } }; From e873255b160346309ee0a938da61d5161526d2c7 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 4 Feb 2018 16:40:22 +0800 Subject: [PATCH 030/361] Update to support gray & grayLarge on iOS & tvOS --- SDWebImage/SDWebImageIndicator.h | 4 ++-- SDWebImage/SDWebImageIndicator.m | 26 +++++++++++++++----------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/SDWebImage/SDWebImageIndicator.h b/SDWebImage/SDWebImageIndicator.h index f6ab96f6..aa62ca5f 100644 --- a/SDWebImage/SDWebImageIndicator.h +++ b/SDWebImage/SDWebImageIndicator.h @@ -59,9 +59,9 @@ @interface SDWebImageActivityIndicator (Conveniences) /// gray-style activity indicator -@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *grayIndicator API_UNAVAILABLE(tvos); +@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *grayIndicator; /// large gray-style activity indicator -@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *grayLargeIndicator API_UNAVAILABLE(ios, tvos); +@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *grayLargeIndicator; /// white-style activity indicator @property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *whiteIndicator; /// large white-style activity indicator diff --git a/SDWebImage/SDWebImageIndicator.m b/SDWebImage/SDWebImageIndicator.m index ba34e61f..fe02f8b0 100644 --- a/SDWebImage/SDWebImageIndicator.m +++ b/SDWebImage/SDWebImageIndicator.m @@ -38,12 +38,7 @@ #if SD_UIKIT - (void)commonInit { -#if SD_TV - UIActivityIndicatorViewStyle style = UIActivityIndicatorViewStyleWhite; -#else - UIActivityIndicatorViewStyle style = UIActivityIndicatorViewStyleGray; -#endif - self.indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:style]; + self.indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; self.indicatorView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin; } #endif @@ -80,21 +75,30 @@ @implementation SDWebImageActivityIndicator (Conveniences) -#if SD_MAC || SD_IOS + (SDWebImageActivityIndicator *)grayIndicator { SDWebImageActivityIndicator *indicator = [SDWebImageActivityIndicator new]; +#if SD_UIKIT +#if SD_IOS + indicator.indicatorView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray; +#else + indicator.indicatorView.color = [UIColor colorWithWhite:0 alpha:0.45]; // Color from `UIActivityIndicatorViewStyleGray` +#endif +#endif return indicator; } -#endif -#if SD_MAC + (SDWebImageActivityIndicator *)grayLargeIndicator { SDWebImageActivityIndicator *indicator = SDWebImageActivityIndicator.grayIndicator; +#if SD_UIKIT + UIColor *grayColor = indicator.indicatorView.color; + indicator.indicatorView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge; + indicator.indicatorView.color = grayColor; +#else indicator.indicatorView.controlSize = NSControlSizeRegular; +#endif [indicator.indicatorView sizeToFit]; return indicator; } -#endif + (SDWebImageActivityIndicator *)whiteIndicator { SDWebImageActivityIndicator *indicator = [SDWebImageActivityIndicator new]; @@ -153,7 +157,7 @@ #if SD_MAC - (void)commonInit { - self.indicatorView = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0, 0, 160, 0)]; + self.indicatorView = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0, 0, 160, 0)]; // Width from `UIProgressView` default width self.indicatorView.style = NSProgressIndicatorStyleBar; self.indicatorView.controlSize = NSControlSizeSmall; [self.indicatorView sizeToFit]; From e5cb977bc8b042e5a8f005b019d147ec5d731484 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 26 Jan 2018 22:40:28 +0800 Subject: [PATCH 031/361] Use property instead of method for UIButton/NSButton current url. --- SDWebImage/NSButton+WebCache.h | 4 ++-- SDWebImage/SDWebImageTransition.h | 11 ----------- SDWebImage/UIButton+WebCache.h | 4 ++-- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/SDWebImage/NSButton+WebCache.h b/SDWebImage/NSButton+WebCache.h index 57f7115e..33f84ba0 100644 --- a/SDWebImage/NSButton+WebCache.h +++ b/SDWebImage/NSButton+WebCache.h @@ -19,7 +19,7 @@ /** * Get the current image URL. */ -- (nullable NSURL *)sd_currentImageURL; +@property (nonatomic, strong, readonly, nullable) NSURL *sd_currentImageURL; /** * Set the button `image` with an `url`. @@ -133,7 +133,7 @@ /** * Get the current alternateImage URL. */ -- (nullable NSURL *)sd_currentAlternateImageURL; +@property (nonatomic, strong, readonly, nullable) NSURL *sd_currentAlternateImageURL; /** * Set the button `alternateImage` with an `url`. diff --git a/SDWebImage/SDWebImageTransition.h b/SDWebImage/SDWebImageTransition.h index 01925947..0c364ea0 100644 --- a/SDWebImage/SDWebImageTransition.h +++ b/SDWebImage/SDWebImageTransition.h @@ -67,8 +67,6 @@ typedef void (^SDWebImageTransitionCompletionBlock)(BOOL finished); @interface SDWebImageTransition (Conveniences) -// class property is available in Xcode 8. We will drop the Xcode 7.3 support in 5.x -#if __has_feature(objc_class_property) /// Fade transition. @property (nonatomic, class, nonnull, readonly) SDWebImageTransition *fadeTransition; /// Flip from left transition. @@ -83,15 +81,6 @@ typedef void (^SDWebImageTransitionCompletionBlock)(BOOL finished); @property (nonatomic, class, nonnull, readonly) SDWebImageTransition *curlUpTransition; /// Curl down transition. @property (nonatomic, class, nonnull, readonly) SDWebImageTransition *curlDownTransition; -#else -+ (nonnull instancetype)fadeTransition; -+ (nonnull instancetype)flipFromLeftTransition; -+ (nonnull instancetype)flipFromRightTransition; -+ (nonnull instancetype)flipFromTopTransition; -+ (nonnull instancetype)flipFromBottomTransition; -+ (nonnull instancetype)curlUpTransition; -+ (nonnull instancetype)curlDownTransition; -#endif @end diff --git a/SDWebImage/UIButton+WebCache.h b/SDWebImage/UIButton+WebCache.h index 61fada62..ffe80651 100644 --- a/SDWebImage/UIButton+WebCache.h +++ b/SDWebImage/UIButton+WebCache.h @@ -22,7 +22,7 @@ /** * Get the current image URL. */ -- (nullable NSURL *)sd_currentImageURL; +@property (nonatomic, strong, readonly, nullable) NSURL *sd_currentImageURL; /** * Get the image URL for a control state. @@ -133,7 +133,7 @@ /** * Get the current background image URL. */ -- (nullable NSURL *)sd_currentBackgroundImageURL; +@property (nonatomic, strong, readonly, nullable) NSURL *sd_currentBackgroundImageURL; /** * Get the background image URL for a control state. From d6a3e2c1aecb6fa8609ecd1bbceb9e77a4f683e4 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 7 Feb 2018 19:59:00 +0800 Subject: [PATCH 032/361] Change the context arg to init method because it should be readonly after created --- SDWebImage/SDWebImageDownloader.m | 3 +-- SDWebImage/SDWebImageDownloaderOperation.h | 29 ++++++++++++++++++---- SDWebImage/SDWebImageDownloaderOperation.m | 11 +++++++- Tests/Tests/SDWebImageDownloaderTests.m | 12 ++++++--- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index a4c28b4d..e776e98f 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -225,9 +225,8 @@ else { request.allHTTPHeaderFields = [sself allHTTPHeaderFields]; } - SDWebImageDownloaderOperation *operation = [[sself.operationClass alloc] initWithRequest:request inSession:sself.session options:options]; + SDWebImageDownloaderOperation *operation = [[sself.operationClass alloc] initWithRequest:request inSession:sself.session options:options context:context]; operation.shouldDecompressImages = sself.shouldDecompressImages; - operation.context = context; if (sself.urlCredential) { operation.credential = sself.urlCredential; diff --git a/SDWebImage/SDWebImageDownloaderOperation.h b/SDWebImage/SDWebImageDownloaderOperation.h index 32d116b0..0355bbf9 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.h +++ b/SDWebImage/SDWebImageDownloaderOperation.h @@ -27,6 +27,11 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification inSession:(nullable NSURLSession *)session options:(SDWebImageDownloaderOptions)options; +- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request + inSession:(nullable NSURLSession *)session + options:(SDWebImageDownloaderOptions)options + context:(nullable SDWebImageContext *)context; + - (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock; @@ -36,9 +41,6 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification - (nullable NSURLCredential *)credential; - (void)setCredential:(nullable NSURLCredential *)value; -- (nullable SDWebImageContext *)context; -- (void)setContext:(nullable SDWebImageContext *)context; - - (BOOL)cancel:(nullable id)token; @end @@ -77,7 +79,7 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification /** * The context for the receiver. */ -@property (copy, nonatomic, nullable) SDWebImageContext *context; +@property (copy, nonatomic, readonly, nullable) SDWebImageContext *context; /** * The expected size of data. @@ -102,7 +104,24 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification */ - (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request inSession:(nullable NSURLSession *)session - options:(SDWebImageDownloaderOptions)options NS_DESIGNATED_INITIALIZER; + options:(SDWebImageDownloaderOptions)options; + +/** + * Initializes a `SDWebImageDownloaderOperation` object + * + * @see SDWebImageDownloaderOperation + * + * @param request the URL request + * @param session the URL session in which this operation will run + * @param options downloader options + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * + * @return the initialized instance + */ +- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request + inSession:(nullable NSURLSession *)session + options:(SDWebImageDownloaderOptions)options + context:(nullable SDWebImageContext *)context NS_DESIGNATED_INITIALIZER; /** * Adds handlers for progress and completion. Returns a tokent that can be passed to -cancel: to cancel this set of diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 19cdb1c5..6b66a1eb 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -25,6 +25,9 @@ typedef NSMutableDictionary SDCallbacksDictionary; @property (strong, nonatomic, nonnull) NSMutableArray *callbackBlocks; +@property (assign, nonatomic, readwrite) SDWebImageDownloaderOptions options; +@property (copy, nonatomic, readwrite, nullable) SDWebImageContext *context; + @property (assign, nonatomic, getter = isExecuting) BOOL executing; @property (assign, nonatomic, getter = isFinished) BOOL finished; @property (strong, nonatomic, nullable) NSMutableData *imageData; @@ -59,13 +62,19 @@ typedef NSMutableDictionary SDCallbacksDictionary; return [self initWithRequest:nil inSession:nil options:0]; } +- (instancetype)initWithRequest:(NSURLRequest *)request inSession:(NSURLSession *)session options:(SDWebImageDownloaderOptions)options { + return [self initWithRequest:request inSession:session options:options]; +} + - (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request inSession:(nullable NSURLSession *)session - options:(SDWebImageDownloaderOptions)options { + options:(SDWebImageDownloaderOptions)options + context:(nullable SDWebImageContext *)context { if ((self = [super init])) { _request = [request copy]; _shouldDecompressImages = YES; _options = options; + _context = [context copy]; _callbackBlocks = [NSMutableArray new]; _executing = NO; _finished = NO; diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index 01bd978b..00b5fe55 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -33,14 +33,20 @@ @property (nonatomic, assign) BOOL shouldDecompressImages; @property (nonatomic, strong, nullable) NSURLCredential *credential; -@property (nonatomic, assign) SDWebImageContext *context; @end @implementation CustomDownloaderOperation -- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)req inSession:(nullable NSURLSession *)ses options:(SDWebImageDownloaderOptions)opt { - if ((self = [super init])) { } +- (instancetype)initWithRequest:(NSURLRequest *)request inSession:(NSURLSession *)session options:(SDWebImageDownloaderOptions)options { + return [self initWithRequest:request inSession:session options:options]; +} + +- (instancetype)initWithRequest:(NSURLRequest *)request inSession:(NSURLSession *)session options:(SDWebImageDownloaderOptions)options context:(SDWebImageContext *)context { + self = [super init]; + if (self) { + + } return self; } From 553ab20c7f94707645241e97746ac74c32dead1c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 13 Feb 2018 21:41:42 +0800 Subject: [PATCH 033/361] Fix test failed --- SDWebImage/SDWebImageDownloaderOperation.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 6b66a1eb..4cbb4bad 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -63,7 +63,7 @@ typedef NSMutableDictionary SDCallbacksDictionary; } - (instancetype)initWithRequest:(NSURLRequest *)request inSession:(NSURLSession *)session options:(SDWebImageDownloaderOptions)options { - return [self initWithRequest:request inSession:session options:options]; + return [self initWithRequest:request inSession:session options:options context:nil]; } - (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request From f115830f970009e8a14b93eaa1a542484ffa368f Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 13 Feb 2018 21:54:21 +0800 Subject: [PATCH 034/361] Fix test again about typo --- Tests/Tests/SDWebImageDownloaderTests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index 00b5fe55..5446b62a 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -39,7 +39,7 @@ @implementation CustomDownloaderOperation - (instancetype)initWithRequest:(NSURLRequest *)request inSession:(NSURLSession *)session options:(SDWebImageDownloaderOptions)options { - return [self initWithRequest:request inSession:session options:options]; + return [self initWithRequest:request inSession:session options:options context:nil]; } - (instancetype)initWithRequest:(NSURLRequest *)request inSession:(NSURLSession *)session options:(SDWebImageDownloaderOptions)options context:(SDWebImageContext *)context { From 1f27d3c15fcc70e6b019a9fb3aab92734a7098d7 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 19 Feb 2018 20:19:14 +0800 Subject: [PATCH 035/361] Rename SDCategoriesTests to SDWebCacheCategoriesTests to make it focus on view category, import KVOController instead of build-in KVO for test --- Tests/Podfile | 1 + .../project.pbxproj | 10 +++--- ...iesTests.m => SDWebCacheCategoriesTests.m} | 34 ++++++------------- 3 files changed, 18 insertions(+), 27 deletions(-) rename Tests/Tests/{SDCategoriesTests.m => SDWebCacheCategoriesTests.m} (86%) diff --git a/Tests/Podfile b/Tests/Podfile index 6610b613..f9b95996 100644 --- a/Tests/Podfile +++ b/Tests/Podfile @@ -8,6 +8,7 @@ workspace '../SDWebImage' target 'Tests' do platform :ios, '8.0' pod 'Expecta' + pod 'KVOController' pod 'SDWebImage/WebP', :path => '../' pod 'SDWebImage/MapKit', :path => '../' pod 'SDWebImage/GIF', :path => '../' diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 3330fb2a..11244477 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -18,7 +18,7 @@ 433BBBB91D7EF8260086B6E9 /* TestImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB81D7EF8260086B6E9 /* TestImage.png */; }; 433BBBBB1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */; }; 4369C1D11D97F80F007E863A /* SDWebImagePrefetcherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */; }; - 4369C2741D9804B1007E863A /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2731D9804B1007E863A /* SDCategoriesTests.m */; }; + 4369C2741D9804B1007E863A /* SDWebCacheCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */; }; 43828A451DA67F9900000E62 /* TestImageLarge.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 43828A441DA67F9900000E62 /* TestImageLarge.jpg */; }; 53F0240D24D359127872F512 /* Pods_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DAAA77E3CA7387F702040D9 /* Pods_Tests.framework */; }; 5F7F38AD1AE2A77A00B0E330 /* TestImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */; }; @@ -46,7 +46,7 @@ 433BBBB81D7EF8260086B6E9 /* TestImage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TestImage.png; sourceTree = ""; }; 433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = MonochromeTestImage.jpg; sourceTree = ""; }; 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImagePrefetcherTests.m; sourceTree = ""; }; - 4369C2731D9804B1007E863A /* SDCategoriesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDCategoriesTests.m; sourceTree = ""; }; + 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebCacheCategoriesTests.m; sourceTree = ""; }; 43828A441DA67F9900000E62 /* TestImageLarge.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = TestImageLarge.jpg; sourceTree = ""; }; 5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = TestImage.jpg; sourceTree = ""; }; 700B00151041D7EE118B1ABD /* Pods-Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.debug.xcconfig"; sourceTree = ""; }; @@ -131,7 +131,7 @@ 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */, 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */, 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */, - 4369C2731D9804B1007E863A /* SDCategoriesTests.m */, + 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */, 37D122861EC48B5E00D98CEB /* SDMockFileManager.h */, 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */, 2D7AF05E1F329763000083C2 /* SDTestCase.h */, @@ -261,6 +261,7 @@ "${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Expecta/Expecta.framework", "${BUILT_PRODUCTS_DIR}/FLAnimatedImage/FLAnimatedImage.framework", + "${BUILT_PRODUCTS_DIR}/KVOController/KVOController.framework", "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", "${BUILT_PRODUCTS_DIR}/libwebp/libwebp.framework", ); @@ -268,6 +269,7 @@ outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Expecta.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FLAnimatedImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KVOController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", ); @@ -286,7 +288,7 @@ 32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */, 1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */, 37D122881EC48B5E00D98CEB /* SDMockFileManager.m in Sources */, - 4369C2741D9804B1007E863A /* SDCategoriesTests.m in Sources */, + 4369C2741D9804B1007E863A /* SDWebCacheCategoriesTests.m in Sources */, 2D7AF0601F329763000083C2 /* SDTestCase.m in Sources */, 4369C1D11D97F80F007E863A /* SDWebImagePrefetcherTests.m in Sources */, DA248D69195475D800390AB0 /* SDImageCacheTests.m in Sources */, diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDWebCacheCategoriesTests.m similarity index 86% rename from Tests/Tests/SDCategoriesTests.m rename to Tests/Tests/SDWebCacheCategoriesTests.m index d619c886..404c5414 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDWebCacheCategoriesTests.m @@ -14,14 +14,13 @@ #import #import #import +#import -static void * SDCategoriesTestsContext = &SDCategoriesTestsContext; - -@interface SDCategoriesTests : SDTestCase +@interface SDWebCacheCategoriesTests : SDTestCase @end -@implementation SDCategoriesTests +@implementation SDWebCacheCategoriesTests - (void)testUIImageViewSetImageWithURL { XCTestExpectation *expectation = [self expectationWithDescription:@"UIImageView setImageWithURL"]; @@ -145,7 +144,13 @@ static void * SDCategoriesTestsContext = &SDCategoriesTestsContext; UIView *view = [[UIView alloc] init]; NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; - [view.sd_imageProgress addObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted)) options:NSKeyValueObservingOptionNew context:SDCategoriesTestsContext]; + [self.KVOController observe:view.sd_imageProgress keyPath:NSStringFromSelector(@selector(fractionCompleted)) options:NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionary * _Nonnull change) { + NSProgress *progress = object; + NSNumber *completedValue = change[NSKeyValueChangeNewKey]; + expect(progress.fractionCompleted).equal(completedValue.doubleValue); + // mark that KVO is called + [progress setUserInfoObject:@(YES) forKey:NSStringFromSelector(@selector(testUIViewImageProgressKVOWork))]; + }]; // Clear the disk cache to force download from network [[SDImageCache sharedImageCache] removeImageForKey:kTestJpegURL withCompletion:^{ @@ -155,24 +160,7 @@ static void * SDCategoriesTestsContext = &SDCategoriesTestsContext; [expectation fulfill]; }]; }]; - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:^(NSError * _Nullable error) { - [view.sd_imageProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted)) context:SDCategoriesTestsContext]; - }]; -} - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context -{ - if (context == SDCategoriesTestsContext) { - if ([keyPath isEqualToString:NSStringFromSelector(@selector(fractionCompleted))]) { - NSProgress *progress = object; - NSNumber *completedValue = change[NSKeyValueChangeNewKey]; - expect(progress.fractionCompleted).equal(completedValue.doubleValue); - // mark that KVO is called - [progress setUserInfoObject:@(YES) forKey:NSStringFromSelector(@selector(testUIViewImageProgressKVOWork))]; - } - } else { - [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; - } + [self waitForExpectationsWithCommonTimeout]; } @end From 150affd201b52a259686b4e1a6b2314693640e39 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 19 Feb 2018 20:38:55 +0800 Subject: [PATCH 036/361] Add new SDCategoriesTests for any other WebCache category tests --- .../project.pbxproj | 4 + Tests/Tests/SDCategoriesTests.m | 84 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 Tests/Tests/SDCategoriesTests.m diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 11244477..5d5782ef 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 2D7AF0601F329763000083C2 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; }; 321259EC1F39E3240096FE0E /* TestImageStatic.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259EB1F39E3240096FE0E /* TestImageStatic.webp */; }; 321259EE1F39E4110096FE0E /* TestImageAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */; }; + 32B99E8B203AF8690017FD66 /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */; }; 32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */; }; 37D122881EC48B5E00D98CEB /* SDMockFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */; }; 433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */; }; @@ -37,6 +38,7 @@ 2D7AF05F1F329763000083C2 /* SDTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDTestCase.m; sourceTree = ""; }; 321259EB1F39E3240096FE0E /* TestImageStatic.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageStatic.webp; sourceTree = ""; }; 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageAnimated.webp; sourceTree = ""; }; + 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDCategoriesTests.m; sourceTree = ""; }; 32E6F0301F3A1B4700A945E6 /* SDWebImageTestDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestDecoder.h; sourceTree = ""; }; 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestDecoder.m; sourceTree = ""; }; 37D122861EC48B5E00D98CEB /* SDMockFileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDMockFileManager.h; sourceTree = ""; }; @@ -132,6 +134,7 @@ 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */, 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */, 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */, + 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */, 37D122861EC48B5E00D98CEB /* SDMockFileManager.h */, 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */, 2D7AF05E1F329763000083C2 /* SDTestCase.h */, @@ -293,6 +296,7 @@ 4369C1D11D97F80F007E863A /* SDWebImagePrefetcherTests.m in Sources */, DA248D69195475D800390AB0 /* SDImageCacheTests.m in Sources */, DA248D6B195476AC00390AB0 /* SDWebImageManagerTests.m in Sources */, + 32B99E8B203AF8690017FD66 /* SDCategoriesTests.m in Sources */, 433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m new file mode 100644 index 00000000..7c9014a1 --- /dev/null +++ b/Tests/Tests/SDCategoriesTests.m @@ -0,0 +1,84 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Matt Galloway + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDTestCase.h" +#import +#import +#import +#import +#import +#import + +@interface SDCategoriesTests : SDTestCase + +@end + +@implementation SDCategoriesTests + +- (void)test01NSDataImageContentTypeCategory { + // Test invalid image data + SDImageFormat format = [NSData sd_imageFormatForImageData:nil]; + expect(format == SDImageFormatUndefined); + + // Test invalid format + CFStringRef type = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatUndefined]; + expect(CFStringCompare(kUTTypePNG, type, 0)).equal(kCFCompareEqualTo); +} + +- (void)test02UIImageMultiFormatCategory { + // Test invalid image data + UIImage *image = [UIImage sd_imageWithData:nil]; + expect(image).to.beNil(); + // Test image encode + image = [UIImage imageWithContentsOfFile:[self testJPEGPath]]; + NSData *data = [image sd_imageData]; + expect(data).notTo.beNil(); + // Test image encode PNG + data = [image sd_imageDataAsFormat:SDImageFormatPNG]; + expect(data).notTo.beNil(); +} + +- (void)test03UIImageGIFCategory { + // Test invalid image data + UIImage *image = [UIImage sd_animatedGIFWithData:nil]; + expect(image).to.beNil(); + // Test valid image data + NSData *data = [NSData dataWithContentsOfFile:[self testGIFPath]]; + image = [UIImage sd_animatedGIFWithData:data]; + expect(image).notTo.beNil(); +} + +- (void)test04UIImageWebPCategory { + // Test invalid image data + UIImage *image = [UIImage sd_imageWithWebPData:nil]; + expect(image).to.beNil(); + // Test valid image data + NSData *data = [NSData dataWithContentsOfFile:[self testWebPPath]]; + image = [UIImage sd_imageWithWebPData:data]; + expect(image).notTo.beNil(); +} + +#pragma mark - Helper + +- (NSString *)testJPEGPath { + NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; + return [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; +} + +- (NSString *)testGIFPath { + NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; + return [testBundle pathForResource:@"TestImage" ofType:@"gif"]; +} + +- (NSString *)testWebPPath { + NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; + return [testBundle pathForResource:@"TestImageStatic" ofType:@"webp"]; +} + +@end From 9d78dccac70c146d063e817b555dfa82b3067a19 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 20 Feb 2018 00:36:52 +0800 Subject: [PATCH 037/361] Add tests scheme for macOS. Because we now support cross-platform, some implementation is different from UIKit & AppKit. So we also need test --- .travis.yml | 3 + Tests/Podfile | 9 + .../project.pbxproj | 277 +++++++++++++++++- .../xcshareddata/xcschemes/Tests Mac.xcscheme | 102 +++++++ Tests/Tests Mac/Info.plist | 22 ++ .../{ => Images}/MonochromeTestImage.jpg | Bin Tests/Tests/{ => Images}/TestImage.gif | Bin Tests/Tests/{ => Images}/TestImage.jpg | Bin Tests/Tests/{ => Images}/TestImage.png | Bin .../Tests/{ => Images}/TestImageAnimated.webp | Bin Tests/Tests/{ => Images}/TestImageLarge.jpg | Bin Tests/Tests/{ => Images}/TestImageStatic.webp | Bin Tests/Tests/SDCategoriesTests.m | 4 +- Tests/Tests/SDImageCacheTests.m | 12 +- Tests/Tests/SDWebCacheCategoriesTests.m | 6 + Tests/Tests/SDWebImageDecoderTests.m | 20 +- Tests/Tests/SDWebImageDownloaderTests.m | 4 +- Tests/Tests/SDWebImageTestDecoder.m | 4 +- 18 files changed, 436 insertions(+), 27 deletions(-) create mode 100644 Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests Mac.xcscheme create mode 100644 Tests/Tests Mac/Info.plist rename Tests/Tests/{ => Images}/MonochromeTestImage.jpg (100%) rename Tests/Tests/{ => Images}/TestImage.gif (100%) rename Tests/Tests/{ => Images}/TestImage.jpg (100%) rename Tests/Tests/{ => Images}/TestImage.png (100%) rename Tests/Tests/{ => Images}/TestImageAnimated.webp (100%) rename Tests/Tests/{ => Images}/TestImageLarge.jpg (100%) rename Tests/Tests/{ => Images}/TestImageStatic.webp (100%) diff --git a/.travis.yml b/.travis.yml index 15f81f64..e1a259b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,6 +47,9 @@ script: - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' -configuration Debug | xcpretty -c + - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX' -sdk macosx -configuration Debug | xcpretty -c + - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX Demo' -sdk macosx -configuration Debug | xcpretty -c + - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests Mac' -sdk macosx -destination 'platform=OS X,arch=x86_64' -configuration Debug | xcpretty -c after_success: - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/Tests/Podfile b/Tests/Podfile index f9b95996..9bb1ac31 100644 --- a/Tests/Podfile +++ b/Tests/Podfile @@ -14,3 +14,12 @@ target 'Tests' do pod 'SDWebImage/GIF', :path => '../' end + +target 'Tests Mac' do + platform :osx, '10.10' + pod 'Expecta' + pod 'KVOController' + pod 'SDWebImage/WebP', :path => '../' + pod 'SDWebImage/MapKit', :path => '../' + +end diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 5d5782ef..b181c4a8 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -7,11 +7,29 @@ objects = { /* Begin PBXBuildFile section */ + 0314594336AFF15E5BB7F0E6 /* Pods_Tests_Mac.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C140E5ED8501C2ABBFD97A24 /* Pods_Tests_Mac.framework */; }; 1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */; }; 2D7AF0601F329763000083C2 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; }; 321259EC1F39E3240096FE0E /* TestImageStatic.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259EB1F39E3240096FE0E /* TestImageStatic.webp */; }; 321259EE1F39E4110096FE0E /* TestImageAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */; }; 32B99E8B203AF8690017FD66 /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */; }; + 32B99E9B203B2EDD0017FD66 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; }; + 32B99E9C203B2EE40017FD66 /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */; }; + 32B99E9D203B2F7D0017FD66 /* SDWebImageTestDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */; }; + 32B99E9E203B2F810017FD66 /* SDMockFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */; }; + 32B99EA2203B31360017FD66 /* MonochromeTestImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */; }; + 32B99EA3203B31360017FD66 /* TestImage.gif in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB61D7EF8200086B6E9 /* TestImage.gif */; }; + 32B99EA4203B31360017FD66 /* TestImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */; }; + 32B99EA5203B31360017FD66 /* TestImageLarge.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 43828A441DA67F9900000E62 /* TestImageLarge.jpg */; }; + 32B99EA6203B31360017FD66 /* TestImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB81D7EF8260086B6E9 /* TestImage.png */; }; + 32B99EA7203B31360017FD66 /* TestImageAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */; }; + 32B99EA8203B31360017FD66 /* TestImageStatic.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259EB1F39E3240096FE0E /* TestImageStatic.webp */; }; + 32B99EA9203B34B60017FD66 /* SDWebImageDecoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */; }; + 32B99EAA203B365F0017FD66 /* SDImageCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA248D68195475D800390AB0 /* SDImageCacheTests.m */; }; + 32B99EAB203B36620017FD66 /* SDWebImageManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA248D6A195476AC00390AB0 /* SDWebImageManagerTests.m */; }; + 32B99EAC203B36650017FD66 /* SDWebImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */; }; + 32B99EAD203B36690017FD66 /* SDWebImagePrefetcherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */; }; + 32B99EAE203B366C0017FD66 /* SDWebCacheCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */; }; 32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */; }; 37D122881EC48B5E00D98CEB /* SDMockFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */; }; 433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */; }; @@ -39,10 +57,13 @@ 321259EB1F39E3240096FE0E /* TestImageStatic.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageStatic.webp; sourceTree = ""; }; 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageAnimated.webp; sourceTree = ""; }; 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDCategoriesTests.m; sourceTree = ""; }; + 32B99E92203B2DF90017FD66 /* Tests Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 32B99E96203B2DF90017FD66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32E6F0301F3A1B4700A945E6 /* SDWebImageTestDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestDecoder.h; sourceTree = ""; }; 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestDecoder.m; sourceTree = ""; }; 37D122861EC48B5E00D98CEB /* SDMockFileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDMockFileManager.h; sourceTree = ""; }; 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDMockFileManager.m; sourceTree = ""; }; + 3B82F4E5C79656CB9C5667F6 /* Pods-Tests Mac.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests Mac.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests Mac/Pods-Tests Mac.debug.xcconfig"; sourceTree = ""; }; 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDecoderTests.m; sourceTree = ""; }; 433BBBB61D7EF8200086B6E9 /* TestImage.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = TestImage.gif; sourceTree = ""; }; 433BBBB81D7EF8260086B6E9 /* TestImage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TestImage.png; sourceTree = ""; }; @@ -50,9 +71,11 @@ 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImagePrefetcherTests.m; sourceTree = ""; }; 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebCacheCategoriesTests.m; sourceTree = ""; }; 43828A441DA67F9900000E62 /* TestImageLarge.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = TestImageLarge.jpg; sourceTree = ""; }; + 5420AE085F25F0E156B00284 /* Pods-Tests Mac.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests Mac.release.xcconfig"; path = "Pods/Target Support Files/Pods-Tests Mac/Pods-Tests Mac.release.xcconfig"; sourceTree = ""; }; 5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = TestImage.jpg; sourceTree = ""; }; 700B00151041D7EE118B1ABD /* Pods-Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.debug.xcconfig"; sourceTree = ""; }; A0085854E7D88C98F2F6C9FC /* Pods-Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.release.xcconfig"; sourceTree = ""; }; + C140E5ED8501C2ABBFD97A24 /* Pods_Tests_Mac.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tests_Mac.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DA248D53195472AA00390AB0 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DA248D56195472AA00390AB0 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; DA248D58195472AA00390AB0 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; @@ -65,6 +88,14 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 32B99E8F203B2DF90017FD66 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0314594336AFF15E5BB7F0E6 /* Pods_Tests_Mac.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DA248D50195472AA00390AB0 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -79,11 +110,35 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 32B99E93203B2DF90017FD66 /* Tests Mac */ = { + isa = PBXGroup; + children = ( + 32B99E96203B2DF90017FD66 /* Info.plist */, + ); + path = "Tests Mac"; + sourceTree = ""; + }; + 32B99EA1203B30DF0017FD66 /* Images */ = { + isa = PBXGroup; + children = ( + 433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */, + 433BBBB61D7EF8200086B6E9 /* TestImage.gif */, + 5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */, + 43828A441DA67F9900000E62 /* TestImageLarge.jpg */, + 433BBBB81D7EF8260086B6E9 /* TestImage.png */, + 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */, + 321259EB1F39E3240096FE0E /* TestImageStatic.webp */, + ); + path = Images; + sourceTree = ""; + }; 3E8D7663CD326C6F44B23889 /* Pods */ = { isa = PBXGroup; children = ( 700B00151041D7EE118B1ABD /* Pods-Tests.debug.xcconfig */, A0085854E7D88C98F2F6C9FC /* Pods-Tests.release.xcconfig */, + 3B82F4E5C79656CB9C5667F6 /* Pods-Tests Mac.debug.xcconfig */, + 5420AE085F25F0E156B00284 /* Pods-Tests Mac.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -92,6 +147,7 @@ isa = PBXGroup; children = ( DA248D5C195472AA00390AB0 /* Tests */, + 32B99E93203B2DF90017FD66 /* Tests Mac */, DA248D55195472AA00390AB0 /* Frameworks */, DA248D54195472AA00390AB0 /* Products */, 3E8D7663CD326C6F44B23889 /* Pods */, @@ -102,6 +158,7 @@ isa = PBXGroup; children = ( DA248D53195472AA00390AB0 /* Tests.xctest */, + 32B99E92203B2DF90017FD66 /* Tests Mac.xctest */, ); name = Products; sourceTree = ""; @@ -113,6 +170,7 @@ DA248D58195472AA00390AB0 /* Foundation.framework */, DA248D5A195472AA00390AB0 /* UIKit.framework */, 1DAAA77E3CA7387F702040D9 /* Pods_Tests.framework */, + C140E5ED8501C2ABBFD97A24 /* Pods_Tests_Mac.framework */, ); name = Frameworks; sourceTree = ""; @@ -120,13 +178,7 @@ DA248D5C195472AA00390AB0 /* Tests */ = { isa = PBXGroup; children = ( - 433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */, - 433BBBB61D7EF8200086B6E9 /* TestImage.gif */, - 5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */, - 43828A441DA67F9900000E62 /* TestImageLarge.jpg */, - 433BBBB81D7EF8260086B6E9 /* TestImage.png */, - 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */, - 321259EB1F39E3240096FE0E /* TestImageStatic.webp */, + 32B99EA1203B30DF0017FD66 /* Images */, DA248D5D195472AA00390AB0 /* Supporting Files */, DA248D68195475D800390AB0 /* SDImageCacheTests.m */, DA248D6A195476AC00390AB0 /* SDWebImageManagerTests.m */, @@ -158,6 +210,26 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 32B99E91203B2DF90017FD66 /* Tests Mac */ = { + isa = PBXNativeTarget; + buildConfigurationList = 32B99E99203B2DF90017FD66 /* Build configuration list for PBXNativeTarget "Tests Mac" */; + buildPhases = ( + C584EBF185E2BBD234CD3350 /* [CP] Check Pods Manifest.lock */, + 32B99E8E203B2DF90017FD66 /* Sources */, + 32B99E8F203B2DF90017FD66 /* Frameworks */, + 32B99E90203B2DF90017FD66 /* Resources */, + 051A05AAEF597E2716FD5814 /* [CP] Embed Pods Frameworks */, + E24640E4B238C940135CC3B6 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Tests Mac"; + productName = "Tests Mac"; + productReference = 32B99E92203B2DF90017FD66 /* Tests Mac.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; DA248D52195472AA00390AB0 /* Tests */ = { isa = PBXNativeTarget; buildConfigurationList = DA248D67195472AA00390AB0 /* Build configuration list for PBXNativeTarget "Tests" */; @@ -185,6 +257,12 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 0900; + TargetAttributes = { + 32B99E91203B2DF90017FD66 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; }; buildConfigurationList = DA248D491954721A00390AB0 /* Build configuration list for PBXProject "SDWebImage Tests" */; compatibilityVersion = "Xcode 3.2"; @@ -199,11 +277,26 @@ projectRoot = ""; targets = ( DA248D52195472AA00390AB0 /* Tests */, + 32B99E91203B2DF90017FD66 /* Tests Mac */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 32B99E90203B2DF90017FD66 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 32B99EA3203B31360017FD66 /* TestImage.gif in Resources */, + 32B99EA4203B31360017FD66 /* TestImage.jpg in Resources */, + 32B99EA6203B31360017FD66 /* TestImage.png in Resources */, + 32B99EA2203B31360017FD66 /* MonochromeTestImage.jpg in Resources */, + 32B99EA8203B31360017FD66 /* TestImageStatic.webp in Resources */, + 32B99EA7203B31360017FD66 /* TestImageAnimated.webp in Resources */, + 32B99EA5203B31360017FD66 /* TestImageLarge.jpg in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DA248D51195472AA00390AB0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -222,6 +315,30 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 051A05AAEF597E2716FD5814 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-Tests Mac/Pods-Tests Mac-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/Expecta-macOS/Expecta.framework", + "${BUILT_PRODUCTS_DIR}/KVOController-macOS/KVOController.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImage-Core-MapKit-WebP/SDWebImage.framework", + "${BUILT_PRODUCTS_DIR}/libwebp-macOS/libwebp.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Expecta.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KVOController.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests Mac/Pods-Tests Mac-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 09522B7196293172D6408744 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -255,6 +372,24 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-resources.sh\"\n"; showEnvVarsInLog = 0; }; + C584EBF185E2BBD234CD3350 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Tests Mac-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; C86216497B5A0BA9501E2C07 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -262,11 +397,11 @@ ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/Expecta/Expecta.framework", + "${BUILT_PRODUCTS_DIR}/Expecta-iOS/Expecta.framework", "${BUILT_PRODUCTS_DIR}/FLAnimatedImage/FLAnimatedImage.framework", - "${BUILT_PRODUCTS_DIR}/KVOController/KVOController.framework", - "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", - "${BUILT_PRODUCTS_DIR}/libwebp/libwebp.framework", + "${BUILT_PRODUCTS_DIR}/KVOController-iOS/KVOController.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImage-Core-GIF-MapKit-WebP/SDWebImage.framework", + "${BUILT_PRODUCTS_DIR}/libwebp-iOS/libwebp.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( @@ -281,9 +416,41 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + E24640E4B238C940135CC3B6 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests Mac/Pods-Tests Mac-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 32B99E8E203B2DF90017FD66 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 32B99EAC203B36650017FD66 /* SDWebImageDownloaderTests.m in Sources */, + 32B99E9C203B2EE40017FD66 /* SDCategoriesTests.m in Sources */, + 32B99EAA203B365F0017FD66 /* SDImageCacheTests.m in Sources */, + 32B99EAD203B36690017FD66 /* SDWebImagePrefetcherTests.m in Sources */, + 32B99EAE203B366C0017FD66 /* SDWebCacheCategoriesTests.m in Sources */, + 32B99E9D203B2F7D0017FD66 /* SDWebImageTestDecoder.m in Sources */, + 32B99E9E203B2F810017FD66 /* SDMockFileManager.m in Sources */, + 32B99EAB203B36620017FD66 /* SDWebImageManagerTests.m in Sources */, + 32B99EA9203B34B60017FD66 /* SDWebImageDecoderTests.m in Sources */, + 32B99E9B203B2EDD0017FD66 /* SDTestCase.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DA248D4F195472AA00390AB0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -315,6 +482,83 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 32B99E97203B2DF90017FD66 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3B82F4E5C79656CB9C5667F6 /* Pods-Tests Mac.debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Manual; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = ""; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = "Tests Mac/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.Tests-Mac"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = macosx; + }; + name = Debug; + }; + 32B99E98203B2DF90017FD66 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5420AE085F25F0E156B00284 /* Pods-Tests Mac.release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Manual; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = ""; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = "Tests Mac/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.Tests-Mac"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = macosx; + }; + name = Release; + }; DA248D4A1954721A00390AB0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -343,6 +587,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.10; ONLY_ACTIVE_ARCH = YES; }; name = Debug; @@ -374,6 +619,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.10; }; name = Release; }; @@ -460,6 +706,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 32B99E99203B2DF90017FD66 /* Build configuration list for PBXNativeTarget "Tests Mac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 32B99E97203B2DF90017FD66 /* Debug */, + 32B99E98203B2DF90017FD66 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; DA248D491954721A00390AB0 /* Build configuration list for PBXProject "SDWebImage Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests Mac.xcscheme b/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests Mac.xcscheme new file mode 100644 index 00000000..b9e1b2ab --- /dev/null +++ b/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests Mac.xcscheme @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Tests Mac/Info.plist b/Tests/Tests Mac/Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/Tests/Tests Mac/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Tests/Tests/MonochromeTestImage.jpg b/Tests/Tests/Images/MonochromeTestImage.jpg similarity index 100% rename from Tests/Tests/MonochromeTestImage.jpg rename to Tests/Tests/Images/MonochromeTestImage.jpg diff --git a/Tests/Tests/TestImage.gif b/Tests/Tests/Images/TestImage.gif similarity index 100% rename from Tests/Tests/TestImage.gif rename to Tests/Tests/Images/TestImage.gif diff --git a/Tests/Tests/TestImage.jpg b/Tests/Tests/Images/TestImage.jpg similarity index 100% rename from Tests/Tests/TestImage.jpg rename to Tests/Tests/Images/TestImage.jpg diff --git a/Tests/Tests/TestImage.png b/Tests/Tests/Images/TestImage.png similarity index 100% rename from Tests/Tests/TestImage.png rename to Tests/Tests/Images/TestImage.png diff --git a/Tests/Tests/TestImageAnimated.webp b/Tests/Tests/Images/TestImageAnimated.webp similarity index 100% rename from Tests/Tests/TestImageAnimated.webp rename to Tests/Tests/Images/TestImageAnimated.webp diff --git a/Tests/Tests/TestImageLarge.jpg b/Tests/Tests/Images/TestImageLarge.jpg similarity index 100% rename from Tests/Tests/TestImageLarge.jpg rename to Tests/Tests/Images/TestImageLarge.jpg diff --git a/Tests/Tests/TestImageStatic.webp b/Tests/Tests/Images/TestImageStatic.webp similarity index 100% rename from Tests/Tests/TestImageStatic.webp rename to Tests/Tests/Images/TestImageStatic.webp diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m index 7c9014a1..8e0a86ce 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDCategoriesTests.m @@ -9,7 +9,9 @@ #import "SDTestCase.h" #import +#if SD_UIKIT #import +#endif #import #import #import @@ -36,7 +38,7 @@ UIImage *image = [UIImage sd_imageWithData:nil]; expect(image).to.beNil(); // Test image encode - image = [UIImage imageWithContentsOfFile:[self testJPEGPath]]; + image = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]]; NSData *data = [image sd_imageData]; expect(data).notTo.beNil(); // Test image encode PNG diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index efec8f06..f46920bb 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -231,10 +231,11 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; expect([cachePath pathExtension]).to.equal(@""); } +#if SD_UIKIT - (void)test40InsertionOfImageData { XCTestExpectation *expectation = [self expectationWithDescription:@"Insertion of image data works"]; - UIImage *image = [UIImage imageWithContentsOfFile:[self testImagePath]]; + UIImage *image = [[UIImage alloc] initWithContentsOfFile:[self testImagePath]]; NSData *imageData = UIImageJPEGRepresentation(image, 1.0); [[SDImageCache sharedImageCache] storeImageDataToDisk:imageData forKey:kImageTestKey error:nil]; @@ -242,7 +243,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; expect(storedImageFromMemory).to.equal(nil); NSString *cachePath = [[SDImageCache sharedImageCache] defaultCachePathForKey:kImageTestKey]; - UIImage *cachedImage = [UIImage imageWithContentsOfFile:cachePath]; + UIImage *cachedImage = [[UIImage alloc] initWithContentsOfFile:cachePath]; NSData *storedImageData = UIImageJPEGRepresentation(cachedImage, 1.0); expect(storedImageData.length).to.beGreaterThan(0); expect(cachedImage.size).to.equal(image.size); @@ -265,7 +266,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; SDWebImageTestDecoder *testDecoder = [[SDWebImageTestDecoder alloc] init]; [[SDWebImageCodersManager sharedInstance] addCoder:testDecoder]; NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"png"]; - UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; + UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; NSString *key = @"TestPNGImageEncodedToDataAndRetrieveToJPEG"; [cache storeImage:image imageData:nil forKey:key toDisk:YES completion:^(NSError * _Nullable error) { @@ -288,7 +289,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; // Decoded result is JPEG NSString * decodedImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"jpg"]; - UIImage *testJPEGImage = [UIImage imageWithContentsOfFile:decodedImagePath]; + UIImage *testJPEGImage = [[UIImage alloc] initWithContentsOfFile:decodedImagePath]; NSData *data1 = UIImagePNGRepresentation(testJPEGImage); NSData *data2 = UIImagePNGRepresentation(diskCacheImage); @@ -306,6 +307,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; [self waitForExpectationsWithCommonTimeout]; } +#endif - (void)test41StoreImageDataToDiskWithError { NSData *imageData = [NSData dataWithContentsOfFile:[self testImagePath]]; @@ -343,7 +345,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (UIImage *)imageForTesting{ static UIImage *reusableImage = nil; if (!reusableImage) { - reusableImage = [UIImage imageWithContentsOfFile:[self testImagePath]]; + reusableImage = [[UIImage alloc] initWithContentsOfFile:[self testImagePath]]; } return reusableImage; } diff --git a/Tests/Tests/SDWebCacheCategoriesTests.m b/Tests/Tests/SDWebCacheCategoriesTests.m index 404c5414..c22c1686 100644 --- a/Tests/Tests/SDWebCacheCategoriesTests.m +++ b/Tests/Tests/SDWebCacheCategoriesTests.m @@ -12,7 +12,9 @@ #import #import #import +#if SD_UIKIT #import +#endif #import #import @@ -38,6 +40,7 @@ [self waitForExpectationsWithCommonTimeout]; } +#if SD_UIKIT - (void)testUIImageViewSetHighlightedImageWithURL { XCTestExpectation *expectation = [self expectationWithDescription:@"UIImageView setHighlightedImageWithURL"]; @@ -53,6 +56,7 @@ }]; [self waitForExpectationsWithCommonTimeout]; } +#endif - (void)testMKAnnotationViewSetImageWithURL { XCTestExpectation *expectation = [self expectationWithDescription:@"MKAnnotationView setImageWithURL"]; @@ -70,6 +74,7 @@ [self waitForExpectationsWithCommonTimeout]; } +#if SD_UIKIT - (void)testUIButtonSetImageWithURLNormalState { XCTestExpectation *expectation = [self expectationWithDescription:@"UIButton setImageWithURL normalState"]; @@ -138,6 +143,7 @@ }]; [self waitForExpectationsWithCommonTimeout]; } +#endif - (void)testUIViewImageProgressKVOWork { XCTestExpectation *expectation = [self expectationWithDescription:@"UIView imageProgressKVO failed"]; diff --git a/Tests/Tests/SDWebImageDecoderTests.m b/Tests/Tests/SDWebImageDecoderTests.m index 947548c8..f7edb845 100644 --- a/Tests/Tests/SDWebImageDecoderTests.m +++ b/Tests/Tests/SDWebImageDecoderTests.m @@ -13,6 +13,8 @@ #import #import #import +#import +#import @interface SDWebImageDecoderTests : SDTestCase @@ -24,9 +26,10 @@ expect([UIImage sd_decodedImageWithImage:nil]).to.beNil(); } +#if SD_UIKIT - (void)test02ThatDecodedImageWithImageWorksWithARegularJPGImage { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"jpg"]; - UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; + UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; UIImage *decodedImage = [UIImage sd_decodedImageWithImage:image]; expect(decodedImage).toNot.beNil(); expect(decodedImage).toNot.equal(image); @@ -36,7 +39,7 @@ - (void)test03ThatDecodedImageWithImageDoesNotDecodeAnimatedImages { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"gif"]; - UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; + UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; UIImage *animatedImage = [UIImage animatedImageWithImages:@[image] duration:0]; UIImage *decodedImage = [UIImage sd_decodedImageWithImage:animatedImage]; expect(decodedImage).toNot.beNil(); @@ -45,7 +48,7 @@ - (void)test04ThatDecodedImageWithImageDoesNotDecodeImagesWithAlpha { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"png"]; - UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; + UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; UIImage *decodedImage = [UIImage sd_decodedImageWithImage:image]; expect(decodedImage).toNot.beNil(); expect(decodedImage).to.equal(image); @@ -53,7 +56,7 @@ - (void)test05ThatDecodedImageWithImageWorksEvenWithMonochromeImage { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"MonochromeTestImage" ofType:@"jpg"]; - UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; + UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; UIImage *decodedImage = [UIImage sd_decodedImageWithImage:image]; expect(decodedImage).toNot.beNil(); expect(decodedImage).toNot.equal(image); @@ -63,7 +66,7 @@ - (void)test06ThatDecodeAndScaleDownImageWorks { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImageLarge" ofType:@"jpg"]; - UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; + UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; UIImage *decodedImage = [UIImage sd_decodedAndScaledDownImageWithImage:image]; expect(decodedImage).toNot.beNil(); expect(decodedImage).toNot.equal(image); @@ -74,7 +77,7 @@ - (void)test07ThatDecodeAndScaleDownImageDoesNotScaleSmallerImage { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"jpg"]; - UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; + UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; UIImage *decodedImage = [UIImage sd_decodedAndScaledDownImageWithImage:image]; expect(decodedImage).toNot.beNil(); expect(decodedImage).toNot.equal(image); @@ -95,6 +98,7 @@ #pragma clang diagnostic pop expect(orientation).to.equal(UIImageOrientationUp); } +#endif - (void)test09ThatStaticWebPCoderWorks { NSURL *staticWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageStatic" withExtension:@"webp"]; @@ -134,15 +138,17 @@ if (isAnimated) { // 2a - check images count > 0 (only for animated images) - expect(inputImage.images.count).to.beGreaterThan(0); + expect(inputImage.sd_isAnimated).to.beTruthy(); // 2b - check image size and scale for each frameImage (only for animated images) +#if SD_UIKIT CGSize imageSize = inputImage.size; CGFloat imageScale = inputImage.scale; [inputImage.images enumerateObjectsUsingBlock:^(UIImage * frameImage, NSUInteger idx, BOOL * stop) { expect(imageSize).to.equal(frameImage.size); expect(imageScale).to.equal(frameImage.scale); }]; +#endif } // 3 - check if we can encode to the original format diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index 5446b62a..a0fabff4 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -362,6 +362,7 @@ [self waitForExpectationsWithCommonTimeout]; } +#if SD_UIKIT - (void)test22ThatCustomDecoderWorksForImageDownload { XCTestExpectation *expectation = [self expectationWithDescription:@"Custom decoder for SDWebImageDownloader not works"]; SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] init]; @@ -371,7 +372,7 @@ // Decoded result is JPEG NSString *testJPEGImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"jpg"]; - UIImage *testJPEGImage = [UIImage imageWithContentsOfFile:testJPEGImagePath]; + UIImage *testJPEGImage = [[UIImage alloc] initWithContentsOfFile:testJPEGImagePath]; [downloader downloadImageWithURL:testImageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { NSData *data1 = UIImagePNGRepresentation(testJPEGImage); @@ -391,5 +392,6 @@ [self waitForExpectationsWithCommonTimeout]; [downloader invalidateSessionAndCancel:YES]; } +#endif @end diff --git a/Tests/Tests/SDWebImageTestDecoder.m b/Tests/Tests/SDWebImageTestDecoder.m index 5bf42da4..c94d7ffe 100644 --- a/Tests/Tests/SDWebImageTestDecoder.m +++ b/Tests/Tests/SDWebImageTestDecoder.m @@ -21,13 +21,13 @@ - (UIImage *)decodedImageWithData:(NSData *)data { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"jpg"]; - UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; + UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; return image; } - (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"gif"]; - UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; + UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; return image; } From 57e56d0154f22ba597758fb1111e9b5df8a0118b Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 20 Feb 2018 01:49:20 +0800 Subject: [PATCH 038/361] Fix the test because one header file not available on iOS. Tests header search path is different from main project --- .travis.yml | 2 +- Tests/Tests/SDCategoriesTests.m | 1 - Tests/Tests/SDWebImageDecoderTests.m | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e1a259b0..ca8bf7e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,7 +46,7 @@ script: - pod install --project-directory=Tests - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c - - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' -configuration Debug | xcpretty -c + - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6s' -configuration Debug | xcpretty -c - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX' -sdk macosx -configuration Debug | xcpretty -c - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX Demo' -sdk macosx -configuration Debug | xcpretty -c - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests Mac' -sdk macosx -destination 'platform=OS X,arch=x86_64' -configuration Debug | xcpretty -c diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m index 8e0a86ce..b49378ed 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDCategoriesTests.m @@ -15,7 +15,6 @@ #import #import #import -#import @interface SDCategoriesTests : SDTestCase diff --git a/Tests/Tests/SDWebImageDecoderTests.m b/Tests/Tests/SDWebImageDecoderTests.m index f7edb845..8ccec289 100644 --- a/Tests/Tests/SDWebImageDecoderTests.m +++ b/Tests/Tests/SDWebImageDecoderTests.m @@ -13,7 +13,9 @@ #import #import #import +#if SD_MAC #import +#endif #import @interface SDWebImageDecoderTests : SDTestCase From 835495a0516fb539cbd7000e2251ee67bd593c71 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 20 Feb 2018 11:41:21 +0800 Subject: [PATCH 039/361] Improve the travis-ci to not clean the build for dynamic framework to speed up the demo build --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index ca8bf7e9..bfef4be0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,10 +37,10 @@ script: - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS' -sdk watchsimulator -configuration Debug | xcpretty -c - echo Build the Demo apps - - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX Demo' -sdk macosx -configuration Debug | xcpretty -c - - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c - - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage TV Demo' -sdk appletvsimulator -configuration Debug | xcpretty -c - - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX Demo' -sdk macosx -configuration Debug | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage TV Demo' -sdk appletvsimulator -configuration Debug | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c - echo Run the tests - pod install --project-directory=Tests From 90632d0abc33b4f8734ed10be7eb65a75b569573 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 20 Feb 2018 12:12:56 +0800 Subject: [PATCH 040/361] Fix prefetcher test to first clear the disk cache, and manager test to only fulfill the finished one --- Tests/Tests/SDWebImageManagerTests.m | 26 ++++++++++++++++--------- Tests/Tests/SDWebImagePrefetcherTests.m | 26 +++++++++++++------------ 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/Tests/Tests/SDWebImageManagerTests.m b/Tests/Tests/SDWebImageManagerTests.m index 561d0ff8..4c79f24f 100644 --- a/Tests/Tests/SDWebImageManagerTests.m +++ b/Tests/Tests/SDWebImageManagerTests.m @@ -110,21 +110,29 @@ - (void)test07ThatLoadImageWithSDWebImageRefreshCachedWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Image download twice with SDWebImageRefresh failed"]; - NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; - [[SDImageCache sharedImageCache] clearDiskOnCompletion:nil]; - + NSURL *originalImageURL = [NSURL URLWithString:@"http://via.placeholder.com/10x10.png"]; + __block BOOL firstCompletion = NO; [[SDWebImageManager sharedManager] loadImageWithURL:originalImageURL options:SDWebImageRefreshCached progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { expect(image).toNot.beNil(); expect(error).to.beNil(); // #1993, load image with SDWebImageRefreshCached twice should not fail if the first time success. - [[SDWebImageManager sharedManager] loadImageWithURL:originalImageURL options:SDWebImageRefreshCached progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { - expect(image).toNot.beNil(); - expect(error).to.beNil(); - [expectation fulfill]; - }]; + // Because we call completion before remove the operation from queue, so need a dispatch to avoid get the same operation again. Attention this trap. + // One way to solve this is use another `NSURL instance` because we use `NSURL` as key but not `NSString`. However, this is implementation detail and no guarantee in the future. + dispatch_async(dispatch_get_main_queue(), ^{ + NSURL *newImageURL = [NSURL URLWithString:@"http://via.placeholder.com/10x10.png"]; + [[SDWebImageManager sharedManager] loadImageWithURL:newImageURL options:SDWebImageRefreshCached progress:nil completed:^(UIImage * _Nullable image2, NSData * _Nullable data2, NSError * _Nullable error2, SDImageCacheType cacheType2, BOOL finished2, NSURL * _Nullable imageURL2) { + expect(image2).toNot.beNil(); + expect(error2).to.beNil(); + if (!firstCompletion) { + firstCompletion = YES; + [expectation fulfill]; + } + }]; + }); }]; - [self waitForExpectationsWithCommonTimeout]; + + [self waitForExpectationsWithTimeout:kAsyncTestTimeout * 2 handler:nil]; } @end diff --git a/Tests/Tests/SDWebImagePrefetcherTests.m b/Tests/Tests/SDWebImagePrefetcherTests.m index 66600add..4079547a 100644 --- a/Tests/Tests/SDWebImagePrefetcherTests.m +++ b/Tests/Tests/SDWebImagePrefetcherTests.m @@ -28,21 +28,23 @@ @"http://via.placeholder.com/30x30.jpg", @"http://via.placeholder.com/40x40.jpg"]; - __block int numberOfPrefetched = 0; + __block NSUInteger numberOfPrefetched = 0; - [[SDWebImagePrefetcher sharedImagePrefetcher] prefetchURLs:imageURLs progress:^(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls) { - numberOfPrefetched += 1; - expect(numberOfPrefetched).to.equal(noOfFinishedUrls); - expect(noOfFinishedUrls).to.beLessThanOrEqualTo(noOfTotalUrls); - expect(noOfTotalUrls).to.equal(imageURLs.count); - } completed:^(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls) { - expect(numberOfPrefetched).to.equal(noOfFinishedUrls); - expect(noOfFinishedUrls).to.equal(imageURLs.count); - expect(noOfSkippedUrls).to.equal(0); - [expectation fulfill]; + [[SDImageCache sharedImageCache] clearDiskOnCompletion:^{ + [[SDWebImagePrefetcher sharedImagePrefetcher] prefetchURLs:imageURLs progress:^(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls) { + numberOfPrefetched += 1; + expect(numberOfPrefetched).to.equal(noOfFinishedUrls); + expect(noOfFinishedUrls).to.beLessThanOrEqualTo(noOfTotalUrls); + expect(noOfTotalUrls).to.equal(imageURLs.count); + } completed:^(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls) { + expect(numberOfPrefetched).to.equal(noOfFinishedUrls); + expect(noOfFinishedUrls).to.equal(imageURLs.count); + expect(noOfSkippedUrls).to.equal(0); + [expectation fulfill]; + }]; }]; - [self waitForExpectationsWithCommonTimeout]; + [self waitForExpectationsWithTimeout:kAsyncTestTimeout * 3 handler:nil]; } - (void)test03PrefetchWithEmptyArrayWillCallTheCompletionWithAllZeros { From 0fa6e88fa1299670ed7e67496d0c76ae6d206d69 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 20 Feb 2018 20:59:16 +0800 Subject: [PATCH 041/361] Disable travis-ci email notification --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index bfef4be0..d2a9bbb1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,8 @@ env: - LC_CTYPE=en_US.UTF-8 - LANG=en_US.UTF-8 +notifications: + email: false before_install: - env From 4557278cb54630f0dc818087898bae09ee7307da Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 21 Feb 2018 19:06:24 +0800 Subject: [PATCH 042/361] Ignore the unguarded availability warning for indicator --- SDWebImage/SDWebImageIndicator.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/SDWebImage/SDWebImageIndicator.m b/SDWebImage/SDWebImageIndicator.m index fe02f8b0..53830a37 100644 --- a/SDWebImage/SDWebImageIndicator.m +++ b/SDWebImage/SDWebImageIndicator.m @@ -165,6 +165,8 @@ } #endif +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" - (void)startAnimatingIndicator { self.indicatorView.hidden = NO; #if SD_UIKIT @@ -207,6 +209,7 @@ self.indicatorView.doubleValue = progress * 100; #endif } +#pragma clang diagnostic pop @end From b831eff3160e165985a6327f9bea29392ab5ba59 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 25 Jan 2018 22:30:05 +0800 Subject: [PATCH 043/361] Refactor the implementation of SDWebImagePrefetcher. Now prefetcher do not cancel previous request and it separate different prefetching process. When you call prefetchURLs for different url lists, you can get callback for different completion block --- SDWebImage/SDWebImagePrefetcher.h | 50 +++--- SDWebImage/SDWebImagePrefetcher.m | 257 ++++++++++++++++++++---------- 2 files changed, 205 insertions(+), 102 deletions(-) diff --git a/SDWebImage/SDWebImagePrefetcher.h b/SDWebImage/SDWebImagePrefetcher.h index 93357f4e..a8eb583c 100644 --- a/SDWebImage/SDWebImagePrefetcher.h +++ b/SDWebImage/SDWebImagePrefetcher.h @@ -11,12 +11,18 @@ @class SDWebImagePrefetcher; +@interface SDWebImagePrefetchToken : NSObject + +@property (nonatomic, copy, readonly, nullable) NSArray *urls; + +@end + @protocol SDWebImagePrefetcherDelegate @optional /** - * Called when an image was prefetched. + * Called when an image was prefetched. Which means it's called when one URL from any of prefetching finished. * * @param imagePrefetcher The current image prefetcher * @param imageURL The image url that was prefetched @@ -26,7 +32,7 @@ - (void)imagePrefetcher:(nonnull SDWebImagePrefetcher *)imagePrefetcher didPrefetchURL:(nullable NSURL *)imageURL finishedCount:(NSUInteger)finishedCount totalCount:(NSUInteger)totalCount; /** - * Called when all images are prefetched. + * Called when all images are prefetched. Which means it's called when all URLs from all of prefetching finished. * @param imagePrefetcher The current image prefetcher * @param totalCount The total number of images that were prefetched (whether successful or not) * @param skippedCount The total number of images that were skipped @@ -54,15 +60,23 @@ typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, @property (nonatomic, assign) NSUInteger maxConcurrentDownloads; /** - * SDWebImageOptions for prefetcher. Defaults to SDWebImageLowPriority. + * The options for prefetcher. Defaults to SDWebImageLowPriority. */ @property (nonatomic, assign) SDWebImageOptions options; /** - * Queue options for Prefetcher. Defaults to Main Queue. + * The context for prefetcher. Defaults to nil. + */ +@property (nonatomic, copy, nullable) SDWebImageContext *context; + +/** + * Queue options for prefetcher when call the progressBlock, completionBlock and delegate methods. Defaults to Main Queue. */ @property (strong, nonatomic, nonnull) dispatch_queue_t prefetcherQueue; +/** + * The delegate for the prefetcher. + */ @property (weak, nonatomic, nullable) id delegate; /** @@ -76,35 +90,35 @@ typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, - (nonnull instancetype)initWithImageManager:(nonnull SDWebImageManager *)manager NS_DESIGNATED_INITIALIZER; /** - * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching, - * currently one image is downloaded at a time, - * and skips images for failed downloads and proceed to the next image in the list. - * Any previously-running prefetch operations are canceled. + * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching. It based on the image manager so the image may from the cache and network according to the `options` property. + * Prefetching is seperate to each other, which means the progressBlock and completionBlock you provide is bind to the prefetching for the list of urls. + * Attention that call this will not cancel previous fetched urls. You should keep the token return by this to cancel or cancel all the prefetch. * * @param urls list of URLs to prefetch + * @return the token to cancel the current prefetching. */ -- (void)prefetchURLs:(nullable NSArray *)urls; +- (nullable SDWebImagePrefetchToken *)prefetchURLs:(nullable NSArray *)urls; /** - * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching, - * currently one image is downloaded at a time, - * and skips images for failed downloads and proceed to the next image in the list. - * Any previously-running prefetch operations are canceled. + * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching. It based on the image manager so the image may from the cache and network according to the `options` property. + * Prefetching is seperate to each other, which means the progressBlock and completionBlock you provide is bind to the prefetching for the list of urls. + * Attention that call this will not cancel previous fetched urls. You should keep the token return by this to cancel or cancel all the prefetch. * * @param urls list of URLs to prefetch * @param progressBlock block to be called when progress updates; * first parameter is the number of completed (successful or not) requests, * second parameter is the total number of images originally requested to be prefetched - * @param completionBlock block to be called when prefetching is completed + * @param completionBlock block to be called when the current prefetching is completed * first param is the number of completed (successful or not) requests, * second parameter is the number of skipped requests + * @return the token to cancel the current prefetching. */ -- (void)prefetchURLs:(nullable NSArray *)urls - progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock - completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock; +- (nullable SDWebImagePrefetchToken *)prefetchURLs:(nullable NSArray *)urls + progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock + completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock; /** - * Remove and cancel queued list + * Remove and cancel all the prefeching for the prefetcher. */ - (void)cancelPrefetching; diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index 18c433e7..d8133403 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -7,17 +7,27 @@ */ #import "SDWebImagePrefetcher.h" +#import + +@interface SDWebImagePrefetchToken () { + @public + int64_t _skippedCount; + int64_t _finishedCount; +} + +@property (nonatomic, copy, readwrite) NSArray *urls; +@property (nonatomic, assign) int64_t totalCount; +@property (nonatomic, strong) NSMutableArray> *operations; +@property (nonatomic, weak) SDWebImagePrefetcher *prefetcher; +@property (nonatomic, copy, nullable) SDWebImagePrefetcherCompletionBlock completionBlock; +@property (nonatomic, copy, nullable) SDWebImagePrefetcherProgressBlock progressBlock; + +@end @interface SDWebImagePrefetcher () @property (strong, nonatomic, nonnull) SDWebImageManager *manager; -@property (strong, atomic, nullable) NSArray *prefetchURLs; // may be accessed from different queue -@property (assign, nonatomic) NSUInteger requestedCount; -@property (assign, nonatomic) NSUInteger skippedCount; -@property (assign, nonatomic) NSUInteger finishedCount; -@property (assign, nonatomic) NSTimeInterval startedTime; -@property (copy, nonatomic, nullable) SDWebImagePrefetcherCompletionBlock completionBlock; -@property (copy, nonatomic, nullable) SDWebImagePrefetcherProgressBlock progressBlock; +@property (strong, atomic, nonnull) NSMutableSet *runningTokens; @end @@ -39,6 +49,7 @@ - (nonnull instancetype)initWithImageManager:(SDWebImageManager *)manager { if ((self = [super init])) { _manager = manager; + _runningTokens = [NSMutableSet set]; _options = SDWebImageLowPriority; _prefetcherQueue = dispatch_get_main_queue(); self.maxConcurrentDownloads = 3; @@ -54,91 +65,169 @@ return self.manager.imageDownloader.maxConcurrentDownloads; } -- (void)startPrefetchingAtIndex:(NSUInteger)index { - NSURL *currentURL; - @synchronized(self) { - if (index >= self.prefetchURLs.count) return; - currentURL = self.prefetchURLs[index]; - self.requestedCount++; - } - [self.manager loadImageWithURL:currentURL options:self.options progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { - if (!finished) return; - self.finishedCount++; - - if (self.progressBlock) { - self.progressBlock(self.finishedCount,(self.prefetchURLs).count); - } - if (!image) { - // Add last failed - self.skippedCount++; - } - if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)]) { - [self.delegate imagePrefetcher:self - didPrefetchURL:currentURL - finishedCount:self.finishedCount - totalCount:self.prefetchURLs.count - ]; - } - if (self.prefetchURLs.count > self.requestedCount) { - dispatch_async(self.prefetcherQueue, ^{ - // we need dispatch to avoid function recursion call. This can prevent stack overflow even for huge urls list - [self startPrefetchingAtIndex:self.requestedCount]; - }); - } else if (self.finishedCount == self.requestedCount) { - [self reportStatus]; - if (self.completionBlock) { - self.completionBlock(self.finishedCount, self.skippedCount); - self.completionBlock = nil; - } - self.progressBlock = nil; - } - }]; +#pragma mark - Prefetch +- (nullable SDWebImagePrefetchToken *)prefetchURLs:(nullable NSArray *)urls { + return [self prefetchURLs:urls progress:nil completed:nil]; } -- (void)reportStatus { - NSUInteger total = (self.prefetchURLs).count; - if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)]) { - [self.delegate imagePrefetcher:self - didFinishWithTotalCount:(total - self.skippedCount) - skippedCount:self.skippedCount - ]; - } -} - -- (void)prefetchURLs:(nullable NSArray *)urls { - [self prefetchURLs:urls progress:nil completed:nil]; -} - -- (void)prefetchURLs:(nullable NSArray *)urls - progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock - completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock { - [self cancelPrefetching]; // Prevent duplicate prefetch request - self.startedTime = CFAbsoluteTimeGetCurrent(); - self.prefetchURLs = urls; - self.completionBlock = completionBlock; - self.progressBlock = progressBlock; - - if (urls.count == 0) { +- (nullable SDWebImagePrefetchToken *)prefetchURLs:(nullable NSArray *)urls + progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock + completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock { + if (!urls || urls.count == 0) { if (completionBlock) { - completionBlock(0,0); - } - } else { - // Starts prefetching from the very first image on the list with the max allowed concurrency - NSUInteger listCount = self.prefetchURLs.count; - for (NSUInteger i = 0; i < self.maxConcurrentDownloads && self.requestedCount < listCount; i++) { - [self startPrefetchingAtIndex:i]; + completionBlock(0, 0); } + return nil; + } + SDWebImagePrefetchToken *token = [SDWebImagePrefetchToken new]; + token.prefetcher = self; + token->_skippedCount = 0; + token->_finishedCount = 0; + token.urls = urls; + token.totalCount = urls.count; + token.operations = [NSMutableArray arrayWithCapacity:urls.count]; + token.progressBlock = progressBlock; + token.completionBlock = completionBlock; + [self addRunningToken:token]; + + for (NSURL *url in urls) { + __weak typeof(self) wself = self; + id operation = [self.manager loadImageWithURL:url options:self.options progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + __strong typeof(wself) sself = wself; + if (!sself) { + return; + } + if (!finished) { + return; + } + OSAtomicIncrement64(&(token->_finishedCount)); + if (error) { + // Add last failed + OSAtomicIncrement64(&(token->_skippedCount)); + } + + // Current operation finished + [sself callProgressBlockForToken:token imageURL:imageURL]; + + if (token->_finishedCount + token->_skippedCount == token.totalCount) { + // All finished + [sself callCompletionBlockForToken:token]; + [sself removeRunningToken:token]; + } + } context:self.context]; + [token.operations addObject:operation]; + } + + return token; +} + +#pragma mark - Cancel +- (void)cancelPrefetching { + @synchronized(self.runningTokens) { + NSSet *copiedTokens = [self.runningTokens copy]; + [copiedTokens makeObjectsPerformSelector:@selector(cancel)]; + [self.runningTokens removeAllObjects]; } } -- (void)cancelPrefetching { - @synchronized(self) { - self.prefetchURLs = nil; - self.skippedCount = 0; - self.requestedCount = 0; - self.finishedCount = 0; +- (void)callProgressBlockForToken:(SDWebImagePrefetchToken *)token imageURL:(NSURL *)url { + if (!token) { + return; } - [self.manager cancelAll]; + BOOL shouldCallDelegate = [self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)]; + dispatch_queue_async_safe(self.prefetcherQueue, ^{ + if (shouldCallDelegate) { + [self.delegate imagePrefetcher:self didPrefetchURL:url finishedCount:[self tokenFinishedCount] totalCount:[self tokenTotalCount]]; + } + if (token.progressBlock) { + token.progressBlock((NSUInteger)token->_finishedCount, (NSUInteger)token.totalCount); + } + }); +} + +- (void)callCompletionBlockForToken:(SDWebImagePrefetchToken *)token { + if (!token) { + return; + } + BOOL shoulCallDelegate = [self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)] && ([self countOfRunningTokens] == 1); // last one + dispatch_queue_async_safe(self.prefetcherQueue, ^{ + if (shoulCallDelegate) { + [self.delegate imagePrefetcher:self didFinishWithTotalCount:[self tokenTotalCount] skippedCount:[self tokenSkippedCount]]; + } + if (token.completionBlock) { + token.completionBlock((NSUInteger)token->_finishedCount, (NSUInteger)token->_skippedCount); + } + }); +} + +#pragma mark - Helper +- (NSUInteger)tokenTotalCount { + NSUInteger tokenTotalCount = 0; + @synchronized (self.runningTokens) { + for (SDWebImagePrefetchToken *token in self.runningTokens) { + tokenTotalCount += token.totalCount; + } + } + return tokenTotalCount; +} + +- (NSUInteger)tokenSkippedCount { + NSUInteger tokenSkippedCount = 0; + @synchronized (self.runningTokens) { + for (SDWebImagePrefetchToken *token in self.runningTokens) { + tokenSkippedCount += token->_skippedCount; + } + } + return tokenSkippedCount; +} + +- (NSUInteger)tokenFinishedCount { + NSUInteger tokenFinishedCount = 0; + @synchronized (self.runningTokens) { + for (SDWebImagePrefetchToken *token in self.runningTokens) { + tokenFinishedCount += token->_finishedCount; + } + } + return tokenFinishedCount; +} + +- (void)addRunningToken:(SDWebImagePrefetchToken *)token { + if (!token) { + return; + } + @synchronized (self.runningTokens) { + [self.runningTokens addObject:token]; + } +} + +- (void)removeRunningToken:(SDWebImagePrefetchToken *)token { + if (!token) { + return; + } + @synchronized (self.runningTokens) { + [self.runningTokens removeObject:token]; + } +} + +- (NSUInteger)countOfRunningTokens { + NSUInteger count = 0; + @synchronized (self.runningTokens) { + count = self.runningTokens.count; + } + return count; +} + +@end + +@implementation SDWebImagePrefetchToken + +- (void)cancel { + @synchronized (self) { + for (id operation in self.operations) { + [operation cancel]; + } + } + [self.prefetcher removeRunningToken:self]; } @end From 69bc9cbd2c9d157d10e8d6bf3ee4ba745cf17c15 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 25 Jan 2018 23:50:40 +0800 Subject: [PATCH 044/361] Update the prefetcher test to ensure that prefetch different urls works and the delegate methods work --- Tests/Tests/SDWebImagePrefetcherTests.m | 85 ++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/Tests/Tests/SDWebImagePrefetcherTests.m b/Tests/Tests/SDWebImagePrefetcherTests.m index 4079547a..0a2bc795 100644 --- a/Tests/Tests/SDWebImagePrefetcherTests.m +++ b/Tests/Tests/SDWebImagePrefetcherTests.m @@ -10,7 +10,12 @@ #import "SDTestCase.h" #import -@interface SDWebImagePrefetcherTests : SDTestCase +@interface SDWebImagePrefetcherTests : SDTestCase + +@property (nonatomic, strong) SDWebImagePrefetcher *prefetcher; +@property (nonatomic, assign) NSUInteger finishedCount; +@property (nonatomic, assign) NSUInteger skippedCount; +@property (nonatomic, assign) NSUInteger totalCount; @end @@ -59,6 +64,82 @@ [self waitForExpectationsWithCommonTimeout]; } -// TODO: test the prefetcher delegate works +- (void)test04PrefetchWithMultipleArrayDifferentQueueWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Prefetch with multiple array at different queue failed"]; + + NSArray *imageURLs1 = @[@"http://via.placeholder.com/20x20.jpg", + @"http://via.placeholder.com/30x30.jpg"]; + NSArray *imageURLs2 = @[@"http://via.placeholder.com/30x30.jpg", + @"http://via.placeholder.com/40x40.jpg"]; + dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); + dispatch_queue_t queue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); + __block int numberOfPrefetched1 = 0; + __block int numberOfPrefetched2 = 0; + __block BOOL prefetchFinished1 = NO; + __block BOOL prefetchFinished2 = NO; + + // Clear the disk cache to make it more realistic for multi-thread environment + [[SDImageCache sharedImageCache] clearDiskOnCompletion:^{ + dispatch_async(queue1, ^{ + [[SDWebImagePrefetcher sharedImagePrefetcher] prefetchURLs:imageURLs1 progress:^(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls) { + numberOfPrefetched1 += 1; + } completed:^(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls) { + expect(numberOfPrefetched1).to.equal(noOfFinishedUrls); + prefetchFinished1 = YES; + // both completion called + if (prefetchFinished1 && prefetchFinished2) { + [expectation fulfill]; + } + }]; + }); + dispatch_async(queue2, ^{ + [[SDWebImagePrefetcher sharedImagePrefetcher] prefetchURLs:imageURLs2 progress:^(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls) { + numberOfPrefetched2 += 1; + } completed:^(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls) { + expect(numberOfPrefetched2).to.equal(noOfFinishedUrls); + prefetchFinished2 = YES; + // both completion called + if (prefetchFinished1 && prefetchFinished2) { + [expectation fulfill]; + } + }]; + }); + }]; + + [self waitForExpectationsWithCommonTimeout]; +} + +- (void)test05PrefecherDelegateWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Prefetcher delegate failed"]; + + NSArray *imageURLs = @[@"http://via.placeholder.com/20x20.jpg", + @"http://via.placeholder.com/30x30.jpg", + @"http://via.placeholder.com/40x40.jpg"]; + self.prefetcher = [SDWebImagePrefetcher new]; + self.prefetcher.delegate = self; + // Current implementation, the delegate method called before the progressBlock and completionBlock + [self.prefetcher prefetchURLs:imageURLs progress:^(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls) { + expect(self.finishedCount).to.equal(noOfFinishedUrls); + expect(self.totalCount).to.equal(noOfTotalUrls); + } completed:^(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls) { + expect(self.finishedCount).to.equal(noOfFinishedUrls); + expect(self.skippedCount).to.equal(noOfSkippedUrls); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithCommonTimeout]; +} + +- (void)imagePrefetcher:(SDWebImagePrefetcher *)imagePrefetcher didFinishWithTotalCount:(NSUInteger)totalCount skippedCount:(NSUInteger)skippedCount { + expect(imagePrefetcher).to.equal(self.prefetcher); + self.skippedCount = skippedCount; + self.totalCount = totalCount; +} + +- (void)imagePrefetcher:(SDWebImagePrefetcher *)imagePrefetcher didPrefetchURL:(NSURL *)imageURL finishedCount:(NSUInteger)finishedCount totalCount:(NSUInteger)totalCount { + expect(imagePrefetcher).to.equal(self.prefetcher); + self.finishedCount = finishedCount; + self.totalCount = totalCount; +} @end From e0ad0711da30cee01a3d11e1154aeee40706eb74 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 10 Mar 2018 00:33:28 +0800 Subject: [PATCH 045/361] Mark two set method in SDWebImageDownloader as property --- SDWebImage/SDWebImageDownloader.h | 43 ++++++++++++------------- SDWebImage/SDWebImageDownloader.m | 5 ++- Tests/Tests/SDWebImageDownloaderTests.m | 1 - 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 6f1ab4f8..9955da1c 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -139,19 +139,26 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB */ @property (readonly, nonatomic, nonnull) NSURLSessionConfiguration *sessionConfiguration; +/** + * Gets/Sets a subclass of `SDWebImageDownloaderOperation` as the default + * `NSOperation` to be used each time SDWebImage constructs a request + * operation to download an image. + * + * @param operationClass The subclass of `SDWebImageDownloaderOperation` to set + * as default. Passing `nil` will revert to `SDWebImageDownloaderOperation`. + */ +@property (assign, nonatomic, nullable) Class operationClass; + +/** + * Gets/Sets the download queue suspension state. + */ +@property (assign, nonatomic, getter=isSuspended) BOOL suspended; /** * Changes download operations execution order. Default value is `SDWebImageDownloaderFIFOExecutionOrder`. */ @property (assign, nonatomic) SDWebImageDownloaderExecutionOrder executionOrder; -/** - * Singleton method, returns the shared instance - * - * @return global shared instance of downloader class - */ -+ (nonnull instancetype)sharedDownloader; - /** * Set the default URL credential to be set for request operations. */ @@ -175,6 +182,13 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB */ @property (nonatomic, copy, nullable) SDWebImageDownloaderHeadersFilterBlock headersFilter; +/** + * Singleton method, returns the shared instance + * + * @return global shared instance of downloader class + */ ++ (nonnull instancetype)sharedDownloader; + /** * Creates an instance of a downloader with specified session configuration. * @note `timeoutIntervalForRequest` is going to be overwritten. @@ -197,16 +211,6 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB */ - (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field; -/** - * Sets a subclass of `SDWebImageDownloaderOperation` as the default - * `NSOperation` to be used each time SDWebImage constructs a request - * operation to download an image. - * - * @param operationClass The subclass of `SDWebImageDownloaderOperation` to set - * as default. Passing `nil` will revert to `SDWebImageDownloaderOperation`. - */ -- (void)setOperationClass:(nullable Class)operationClass; - /** * Creates a SDWebImageDownloader async downloader instance with a given URL * @@ -263,11 +267,6 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB */ - (void)cancel:(nullable SDWebImageDownloadToken *)token; -/** - * Sets the download queue suspension state - */ -- (void)setSuspended:(BOOL)suspended; - /** * Cancels all download operations in the queue */ diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 03b2354b..ba4c6a5d 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -36,7 +36,6 @@ @property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue; @property (weak, nonatomic, nullable) NSOperation *lastAddedOperation; -@property (assign, nonatomic, nullable) Class operationClass; @property (strong, nonatomic, nonnull) NSMutableDictionary *URLOperations; @property (strong, nonatomic, nullable) SDHTTPHeadersMutableDictionary *HTTPHeaders; @property (strong, nonatomic, nonnull) dispatch_semaphore_t operationsLock; // a lock to keep the access to `URLOperations` thread-safe @@ -309,6 +308,10 @@ return token; } +- (BOOL)isSuspended { + return self.downloadQueue.isSuspended; +} + - (void)setSuspended:(BOOL)suspended { self.downloadQueue.suspended = suspended; } diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index a0fabff4..0333f2d3 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -17,7 +17,6 @@ * Category for SDWebImageDownloader so we can access the operationClass */ @interface SDWebImageDownloader () -@property (assign, nonatomic, nullable) Class operationClass; @property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue; - (nullable SDWebImageDownloadToken *)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock From c9dfe39e36422398757fe9bf55002fac9ea49c58 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 11 Mar 2018 15:51:49 +0800 Subject: [PATCH 046/361] Change all sharedInstance from method to class property --- Examples/SDWebImage OSX Demo/ViewController.m | 2 +- SDWebImage/SDImageCache.h | 4 +--- SDWebImage/SDImageCache.m | 6 +++--- SDWebImage/SDWebImageCodersManager.h | 4 ++-- SDWebImage/SDWebImageCodersManager.m | 2 +- SDWebImage/SDWebImageDownloader.h | 6 ++---- SDWebImage/SDWebImageDownloaderOperation.m | 8 ++++---- SDWebImage/SDWebImageGIFCoder.h | 2 +- SDWebImage/SDWebImageImageIOCoder.h | 2 +- SDWebImage/SDWebImageManager.h | 6 ++---- SDWebImage/SDWebImagePrefetcher.h | 4 ++-- SDWebImage/SDWebImageWebPCoder.h | 2 +- SDWebImage/UIImage+ForceDecode.m | 4 ++-- SDWebImage/UIImage+MultiFormat.m | 4 ++-- Tests/Tests/SDImageCacheTests.m | 4 ++-- Tests/Tests/SDWebImageDownloaderTests.m | 4 ++-- 16 files changed, 29 insertions(+), 35 deletions(-) diff --git a/Examples/SDWebImage OSX Demo/ViewController.m b/Examples/SDWebImage OSX Demo/ViewController.m index 349f662c..d3d5e298 100644 --- a/Examples/SDWebImage OSX Demo/ViewController.m +++ b/Examples/SDWebImage OSX Demo/ViewController.m @@ -26,7 +26,7 @@ [super viewDidLoad]; //Add GIF coder for better animated image rendering - [[SDWebImageCodersManager sharedInstance] addCoder:[SDWebImageGIFCoder sharedCoder]]; + [[SDWebImageCodersManager sharedManager] addCoder:[SDWebImageGIFCoder sharedCoder]]; // NOTE: https links or authentication ones do not work (there is a crash) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 192a9c49..4d51c03b 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -62,10 +62,8 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er /** * Returns global shared cache instance - * - * @return SDImageCache global instance */ -+ (nonnull instancetype)sharedImageCache; +@property (nonatomic, class, readonly, nonnull) SDImageCache *sharedImageCache; /** * Init a new cache store with a specific namespace diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index c214fb39..68f5f459 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -298,7 +298,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } else { format = SDImageFormatJPEG; } - data = [[SDWebImageCodersManager sharedInstance] encodedDataWithImage:image format:format]; + data = [[SDWebImageCodersManager sharedManager] encodedDataWithImage:image format:format]; } [self _storeImageDataToDisk:data forKey:key error:&writeError]; } @@ -475,10 +475,10 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { - (nullable UIImage *)diskImageForKey:(nullable NSString *)key data:(nullable NSData *)data { if (data) { - UIImage *image = [[SDWebImageCodersManager sharedInstance] decodedImageWithData:data]; + UIImage *image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:data]; image = [self scaledImageForKey:key image:image]; if (self.config.shouldDecompressImages) { - image = [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&data options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}]; + image = [[SDWebImageCodersManager sharedManager] decompressedImageWithImage:image data:&data options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}]; } return image; } else { diff --git a/SDWebImage/SDWebImageCodersManager.h b/SDWebImage/SDWebImageCodersManager.h index 5c3d4b37..d74eb8c6 100644 --- a/SDWebImage/SDWebImageCodersManager.h +++ b/SDWebImage/SDWebImageCodersManager.h @@ -32,9 +32,9 @@ @interface SDWebImageCodersManager : NSObject /** - Shared reusable instance + Returns the global shared coders manager instance. */ -+ (nonnull instancetype)sharedInstance; +@property (nonatomic, class, readonly, nonnull) SDWebImageCodersManager *sharedManager; /** All coders in coders manager. The coders array is a priority queue, which means the later added coder will have the highest priority diff --git a/SDWebImage/SDWebImageCodersManager.m b/SDWebImage/SDWebImageCodersManager.m index 6134aa88..048d4aab 100644 --- a/SDWebImage/SDWebImageCodersManager.m +++ b/SDWebImage/SDWebImageCodersManager.m @@ -22,7 +22,7 @@ @implementation SDWebImageCodersManager -+ (nonnull instancetype)sharedInstance { ++ (nonnull instancetype)sharedManager { static dispatch_once_t once; static id instance; dispatch_once(&once, ^{ diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 9955da1c..2dc841a7 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -183,11 +183,9 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB @property (nonatomic, copy, nullable) SDWebImageDownloaderHeadersFilterBlock headersFilter; /** - * Singleton method, returns the shared instance - * - * @return global shared instance of downloader class + * Returns the global shared downloader instance */ -+ (nonnull instancetype)sharedDownloader; +@property (nonatomic, class, readonly, nonnull) SDWebImageDownloader *sharedDownloader; /** * Creates an instance of a downloader with specified session configuration. diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 741c3d3d..1ee0c7c9 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -345,7 +345,7 @@ didReceiveResponse:(NSURLResponse *)response if (!self.progressiveCoder) { // We need to create a new instance for progressive decoding to avoid conflicts - for (idcoder in [SDWebImageCodersManager sharedInstance].coders) { + for (idcoder in [SDWebImageCodersManager sharedManager].coders) { if ([coder conformsToProtocol:@protocol(SDWebImageProgressiveCoder)] && [((id)coder) canIncrementallyDecodeFromData:imageData]) { self.progressiveCoder = [[[coder class] alloc] init]; @@ -361,7 +361,7 @@ didReceiveResponse:(NSURLResponse *)response NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; image = [self scaledImageForKey:key image:image]; if (self.shouldDecompressImages) { - image = [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&imageData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}]; + image = [[SDWebImageCodersManager sharedManager] decompressedImageWithImage:image data:&imageData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}]; } // We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding. @@ -427,7 +427,7 @@ didReceiveResponse:(NSURLResponse *)response } else { // decode the image in coder queue dispatch_async(self.coderQueue, ^{ - UIImage *image = [[SDWebImageCodersManager sharedInstance] decodedImageWithData:imageData]; + UIImage *image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData]; NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; image = [self scaledImageForKey:key image:image]; @@ -447,7 +447,7 @@ didReceiveResponse:(NSURLResponse *)response if (shouldDecode) { if (self.shouldDecompressImages) { BOOL shouldScaleDown = self.options & SDWebImageDownloaderScaleDownLargeImages; - image = [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&imageData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(shouldScaleDown)}]; + image = [[SDWebImageCodersManager sharedManager] decompressedImageWithImage:image data:&imageData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(shouldScaleDown)}]; } } CGSize imageSize = image.size; diff --git a/SDWebImage/SDWebImageGIFCoder.h b/SDWebImage/SDWebImageGIFCoder.h index 30521f9e..f6a3dc5d 100644 --- a/SDWebImage/SDWebImageGIFCoder.h +++ b/SDWebImage/SDWebImageGIFCoder.h @@ -18,6 +18,6 @@ */ @interface SDWebImageGIFCoder : NSObject -+ (nonnull instancetype)sharedCoder; +@property (nonatomic, class, readonly, nonnull) SDWebImageGIFCoder *sharedCoder; @end diff --git a/SDWebImage/SDWebImageImageIOCoder.h b/SDWebImage/SDWebImageImageIOCoder.h index 04f68fb9..b43c9c0d 100644 --- a/SDWebImage/SDWebImageImageIOCoder.h +++ b/SDWebImage/SDWebImageImageIOCoder.h @@ -25,6 +25,6 @@ */ @interface SDWebImageImageIOCoder : NSObject -+ (nonnull instancetype)sharedCoder; +@property (nonatomic, class, readonly, nonnull) SDWebImageImageIOCoder *sharedCoder; @end diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 4d954a15..adb7ab39 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -213,11 +213,9 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; @property (nonatomic, copy, nullable) SDWebImageCacheKeyFilterBlock cacheKeyFilter; /** - * Returns global SDWebImageManager instance. - * - * @return SDWebImageManager shared instance + * Returns global shared manager instance. */ -+ (nonnull instancetype)sharedManager; +@property (nonatomic, class, readonly, nonnull) SDWebImageManager *sharedManager; /** * Allows to specify instance of cache and image downloader used with image manager. diff --git a/SDWebImage/SDWebImagePrefetcher.h b/SDWebImage/SDWebImagePrefetcher.h index a8eb583c..cba81edf 100644 --- a/SDWebImage/SDWebImagePrefetcher.h +++ b/SDWebImage/SDWebImagePrefetcher.h @@ -80,9 +80,9 @@ typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, @property (weak, nonatomic, nullable) id delegate; /** - * Return the global image prefetcher instance. + * Returns the global shared image prefetcher instance. */ -+ (nonnull instancetype)sharedImagePrefetcher; +@property (nonatomic, class, readonly, nonnull) SDWebImagePrefetcher *sharedImagePrefetcher; /** * Allows you to instantiate a prefetcher with any arbitrary image manager. diff --git a/SDWebImage/SDWebImageWebPCoder.h b/SDWebImage/SDWebImageWebPCoder.h index 634b5751..05f51856 100644 --- a/SDWebImage/SDWebImageWebPCoder.h +++ b/SDWebImage/SDWebImageWebPCoder.h @@ -16,7 +16,7 @@ */ @interface SDWebImageWebPCoder : NSObject -+ (nonnull instancetype)sharedCoder; +@property (nonatomic, class, readonly, nonnull) SDWebImageWebPCoder *sharedCoder; @end diff --git a/SDWebImage/UIImage+ForceDecode.m b/SDWebImage/UIImage+ForceDecode.m index 2f25f047..27be405b 100644 --- a/SDWebImage/UIImage+ForceDecode.m +++ b/SDWebImage/UIImage+ForceDecode.m @@ -16,7 +16,7 @@ return nil; } NSData *tempData; - return [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&tempData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}]; + return [[SDWebImageCodersManager sharedManager] decompressedImageWithImage:image data:&tempData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}]; } + (UIImage *)sd_decodedAndScaledDownImageWithImage:(UIImage *)image { @@ -24,7 +24,7 @@ return nil; } NSData *tempData; - return [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&tempData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(YES)}]; + return [[SDWebImageCodersManager sharedManager] decompressedImageWithImage:image data:&tempData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(YES)}]; } @end diff --git a/SDWebImage/UIImage+MultiFormat.m b/SDWebImage/UIImage+MultiFormat.m index 8abe595b..7007c45b 100644 --- a/SDWebImage/UIImage+MultiFormat.m +++ b/SDWebImage/UIImage+MultiFormat.m @@ -12,7 +12,7 @@ @implementation UIImage (MultiFormat) + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data { - return [[SDWebImageCodersManager sharedInstance] decodedImageWithData:data]; + return [[SDWebImageCodersManager sharedManager] decodedImageWithData:data]; } - (nullable NSData *)sd_imageData { @@ -22,7 +22,7 @@ - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat { NSData *imageData = nil; if (self) { - imageData = [[SDWebImageCodersManager sharedInstance] encodedDataWithImage:self format:imageFormat]; + imageData = [[SDWebImageCodersManager sharedManager] encodedDataWithImage:self format:imageFormat]; } return imageData; } diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index f46920bb..0f5a09fd 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -264,7 +264,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; XCTestExpectation *expectation = [self expectationWithDescription:@"Custom decoder for SDImageCache not works"]; SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"TestDecode"]; SDWebImageTestDecoder *testDecoder = [[SDWebImageTestDecoder alloc] init]; - [[SDWebImageCodersManager sharedInstance] addCoder:testDecoder]; + [[SDWebImageCodersManager sharedManager] addCoder:testDecoder]; NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"png"]; UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; NSString *key = @"TestPNGImageEncodedToDataAndRetrieveToJPEG"; @@ -298,7 +298,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; XCTFail(@"Custom decoder not work for SDImageCache, check -[SDWebImageTestDecoder decodedImageWithData:]"); } - [[SDWebImageCodersManager sharedInstance] removeCoder:testDecoder]; + [[SDWebImageCodersManager sharedManager] removeCoder:testDecoder]; [[SDImageCache sharedImageCache] removeImageForKey:key withCompletion:^{ [expectation fulfill]; diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index 0333f2d3..8221d9c9 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -366,7 +366,7 @@ XCTestExpectation *expectation = [self expectationWithDescription:@"Custom decoder for SDWebImageDownloader not works"]; SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] init]; SDWebImageTestDecoder *testDecoder = [[SDWebImageTestDecoder alloc] init]; - [[SDWebImageCodersManager sharedInstance] addCoder:testDecoder]; + [[SDWebImageCodersManager sharedManager] addCoder:testDecoder]; NSURL * testImageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImage" withExtension:@"png"]; // Decoded result is JPEG @@ -384,7 +384,7 @@ if (![str1 isEqualToString:str2]) { XCTFail(@"The image data is not modified by the custom decoder, check -[SDWebImageTestDecoder decompressedImageWithImage:data:options:]"); } - [[SDWebImageCodersManager sharedInstance] removeCoder:testDecoder]; + [[SDWebImageCodersManager sharedManager] removeCoder:testDecoder]; [expectation fulfill]; }]; From 96990ab9e72286011bc761214f150989b3c97e3b Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 11 Mar 2018 19:12:03 +0800 Subject: [PATCH 047/361] Update the comments for `operationClass` --- SDWebImage/SDWebImageDownloader.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 2dc841a7..a2cbb2a4 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -144,8 +144,7 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB * `NSOperation` to be used each time SDWebImage constructs a request * operation to download an image. * - * @param operationClass The subclass of `SDWebImageDownloaderOperation` to set - * as default. Passing `nil` will revert to `SDWebImageDownloaderOperation`. + * @note Passing `NSOperation` to set as default. Passing `nil` will revert to `SDWebImageDownloaderOperation`. */ @property (assign, nonatomic, nullable) Class operationClass; From b4ea87f6c5d5238befa0f07a5e32ddf492ff47ed Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 11 Feb 2018 23:36:58 +0800 Subject: [PATCH 048/361] Add image transformer protocol and class. Add UIImage+Transformer category including common image geometry, tinting, blur effect processor. --- SDWebImage.xcodeproj/project.pbxproj | 56 +++ SDWebImage/SDWebImageCompat.h | 3 + SDWebImage/SDWebImageTransformer.h | 139 ++++++++ SDWebImage/SDWebImageTransformer.m | 309 ++++++++++++++++ SDWebImage/UIImage+Transform.h | 126 +++++++ SDWebImage/UIImage+Transform.m | 505 +++++++++++++++++++++++++++ 6 files changed, 1138 insertions(+) create mode 100644 SDWebImage/SDWebImageTransformer.h create mode 100644 SDWebImage/SDWebImageTransformer.m create mode 100644 SDWebImage/UIImage+Transform.h create mode 100644 SDWebImage/UIImage+Transform.m diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 21cf1e9d..1ff4efb0 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -388,6 +388,30 @@ 32CF1C101FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; 32CF1C111FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; 32CF1C121FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; + 32F7C06F2030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0702030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0712030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0722030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0732030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0742030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0752030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; }; + 32F7C0762030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; }; + 32F7C0772030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; }; + 32F7C0782030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; }; + 32F7C0792030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; }; + 32F7C07A2030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; }; + 32F7C07E2030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; + 32F7C07F2030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; + 32F7C0802030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; + 32F7C0812030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; + 32F7C0822030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; + 32F7C0832030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; + 32F7C0842030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; }; + 32F7C0852030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; }; + 32F7C0862030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; }; + 32F7C0872030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; }; + 32F7C0882030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; }; + 32F7C0892030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; }; 4314D1231D0E0E3B004B36C9 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D86148C56230056699D /* SDImageCache.m */; }; 4314D1311D0E0E3B004B36C9 /* SDWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8C148C56230056699D /* SDWebImageDownloader.m */; }; 4314D1341D0E0E3B004B36C9 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB921762547C00698166 /* UIImage+WebP.m */; }; @@ -1391,6 +1415,10 @@ 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageIndicator.m; sourceTree = ""; }; 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoderHelper.h; sourceTree = ""; }; 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCoderHelper.m; sourceTree = ""; }; + 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTransformer.h; sourceTree = ""; }; + 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransformer.m; sourceTree = ""; }; + 32F7C07C2030719600873181 /* UIImage+Transform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Transform.m"; sourceTree = ""; }; + 32F7C07D2030719600873181 /* UIImage+Transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Transform.h"; sourceTree = ""; }; 4314D1991D0E0E3B004B36C9 /* libSDWebImage watchOS static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libSDWebImage watchOS static.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 431BB7031D06D2C1006A3455 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4369C2751D9807EC007E863A /* UIView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+WebCache.h"; path = "SDWebImage/UIView+WebCache.h"; sourceTree = ""; }; @@ -1835,6 +1863,8 @@ 53EDFB921762547C00698166 /* UIImage+WebP.m */, 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */, 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */, + 32F7C07D2030719600873181 /* UIImage+Transform.h */, + 32F7C07C2030719600873181 /* UIImage+Transform.m */, 4397D2F41D0DE2DF00BB2784 /* NSImage+Additions.h */, 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */, AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */, @@ -1878,6 +1908,8 @@ 325312C7200F09910046BF1E /* SDWebImageTransition.m */, 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */, 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */, + 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */, + 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */, ); name = Utils; sourceTree = ""; @@ -2125,11 +2157,13 @@ 80377C5F1F2F666300F89830 /* utils.h in Headers */, 80377C5B1F2F666300F89830 /* rescaler_utils.h in Headers */, 323F8BF91F38EF770092B609 /* animi.h in Headers */, + 32F7C0872030719600873181 /* UIImage+Transform.h in Headers */, 80377C4F1F2F666300F89830 /* filters_utils.h in Headers */, 80377C4C1F2F666300F89830 /* color_cache_utils.h in Headers */, 32C0FDE42013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 321E60C11F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 80377DBE1F2F66A700F89830 /* dsp.h in Headers */, + 32F7C0722030114C00873181 /* SDWebImageTransformer.h in Headers */, 80377EB81F2F66D400F89830 /* alphai_dec.h in Headers */, 00733A6D1BC4880E00A5A117 /* UIImage+GIF.h in Headers */, 80377C551F2F666300F89830 /* quant_levels_dec_utils.h in Headers */, @@ -2152,8 +2186,10 @@ 321E60BF1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 80377EA61F2F66D400F89830 /* webpi_dec.h in Headers */, 807A12291F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, + 32F7C0852030719600873181 /* UIImage+Transform.h in Headers */, 80377C141F2F666300F89830 /* bit_reader_utils.h in Headers */, 323F8C0F1F38EF770092B609 /* muxi.h in Headers */, + 32F7C0702030114C00873181 /* SDWebImageTransformer.h in Headers */, 80377C2B1F2F666300F89830 /* utils.h in Headers */, 4314D1621D0E0E3B004B36C9 /* mux_types.h in Headers */, 4314D1631D0E0E3B004B36C9 /* demux.h in Headers */, @@ -2255,6 +2291,7 @@ 80377E211F2F66A800F89830 /* neon.h in Headers */, 80377C711F2F666400F89830 /* quant_levels_utils.h in Headers */, 323F8B541F38EF770092B609 /* backward_references_enc.h in Headers */, + 32F7C0882030719600873181 /* UIImage+Transform.h in Headers */, 43A62A1F1D0E0A800089D7DD /* mux.h in Headers */, 431BB6E91D06D2C1006A3455 /* SDWebImageDownloaderOperation.h in Headers */, 80377ED41F2F66D500F89830 /* vp8li_dec.h in Headers */, @@ -2289,6 +2326,7 @@ 323F8BFA1F38EF770092B609 /* animi.h in Headers */, 431BB6F91D06D2C1006A3455 /* UIImage+GIF.h in Headers */, 321E60B41F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, + 32F7C0732030114C00873181 /* SDWebImageTransformer.h in Headers */, 431BB6FA1D06D2C1006A3455 /* SDWebImageDownloader.h in Headers */, 80377DF51F2F66A800F89830 /* common_sse2.h in Headers */, 323F8BDC1F38EF770092B609 /* vp8i_enc.h in Headers */, @@ -2305,6 +2343,7 @@ 80377ED81F2F66D500F89830 /* alphai_dec.h in Headers */, 321E60A71F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, 324DF4B9200A14DC008A84CC /* SDWebImageDefine.h in Headers */, + 32F7C0892030719600873181 /* UIImage+Transform.h in Headers */, 80377EDA1F2F66D500F89830 /* common_dec.h in Headers */, 80377EE61F2F66D500F89830 /* webpi_dec.h in Headers */, 4397D2BA1D0DDD8C00BB2784 /* demux.h in Headers */, @@ -2340,6 +2379,7 @@ 32CF1C0C1FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, 43A918691D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 4397D2D81D0DDD8C00BB2784 /* UIButton+WebCache.h in Headers */, + 32F7C0742030114C00873181 /* SDWebImageTransformer.h in Headers */, 80377E641F2F66A800F89830 /* mips_macro.h in Headers */, 323F8BDD1F38EF770092B609 /* vp8i_enc.h in Headers */, 323F8B671F38EF770092B609 /* cost_enc.h in Headers */, @@ -2452,11 +2492,13 @@ 4A2CAE311AB4BB7500B6BC39 /* UIImage+WebP.h in Headers */, 323F8BF81F38EF770092B609 /* animi.h in Headers */, 80377C351F2F666300F89830 /* filters_utils.h in Headers */, + 32F7C0862030719600873181 /* UIImage+Transform.h in Headers */, 80377C321F2F666300F89830 /* color_cache_utils.h in Headers */, 321E60C01F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 32C0FDE32013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 80377D791F2F66A700F89830 /* dsp.h in Headers */, 80377EA81F2F66D400F89830 /* alphai_dec.h in Headers */, + 32F7C0712030114C00873181 /* SDWebImageTransformer.h in Headers */, 4A2CAE2D1AB4BB7500B6BC39 /* UIImage+GIF.h in Headers */, 80377C3B1F2F666300F89830 /* quant_levels_dec_utils.h in Headers */, 80377EB11F2F66D400F89830 /* vp8_dec.h in Headers */, @@ -2473,6 +2515,7 @@ 431738BE1CDFC2660008FEB9 /* demux.h in Headers */, 80377BFC1F2F665300F89830 /* bit_writer_utils.h in Headers */, 32CF1C071FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, + 32F7C0842030719600873181 /* UIImage+Transform.h in Headers */, 431738BF1CDFC2660008FEB9 /* encode.h in Headers */, 53761316155AD0D5005750A4 /* SDImageCache.h in Headers */, 323F8C0E1F38EF770092B609 /* muxi.h in Headers */, @@ -2507,6 +2550,7 @@ 80377C0F1F2F665300F89830 /* thread_utils.h in Headers */, 321E60BE1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 5376131E155AD0D5005750A4 /* SDWebImagePrefetcher.h in Headers */, + 32F7C06F2030114C00873181 /* SDWebImageTransformer.h in Headers */, 324DF4B4200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 80377CE11F2F66A100F89830 /* common_sse2.h in Headers */, 80377C0B1F2F665300F89830 /* random_utils.h in Headers */, @@ -2796,6 +2840,7 @@ 80377DAE1F2F66A700F89830 /* argb_sse2.c in Sources */, 323F8B7D1F38EF770092B609 /* frame_enc.c in Sources */, 80377EBB1F2F66D500F89830 /* frame_dec.c in Sources */, + 32F7C0782030114C00873181 /* SDWebImageTransformer.m in Sources */, 80377DAF1F2F66A700F89830 /* argb.c in Sources */, 323F8B6B1F38EF770092B609 /* delta_palettization_enc.c in Sources */, 00733A5B1BC4880000A5A117 /* NSData+ImageContentType.m in Sources */, @@ -2828,6 +2873,7 @@ 80377DE31F2F66A700F89830 /* upsampling_mips_dsp_r2.c in Sources */, 80377EBD1F2F66D500F89830 /* io_dec.c in Sources */, 80377EBC1F2F66D500F89830 /* idec_dec.c in Sources */, + 32F7C0812030719600873181 /* UIImage+Transform.m in Sources */, 323F8B991F38EF770092B609 /* near_lossless_enc.c in Sources */, 80377DE81F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */, 80377EC31F2F66D500F89830 /* vp8l_dec.c in Sources */, @@ -3016,6 +3062,7 @@ 3237F9EC20161AE000A88143 /* NSImage+Additions.m in Sources */, 4314D1411D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.m in Sources */, 80377D561F2F66A700F89830 /* rescaler_neon.c in Sources */, + 32F7C0762030114C00873181 /* SDWebImageTransformer.m in Sources */, 80377D551F2F66A700F89830 /* rescaler_msa.c in Sources */, 80377D5E1F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */, 80377D611F2F66A700F89830 /* yuv.c in Sources */, @@ -3056,6 +3103,7 @@ 4314D1551D0E0E3B004B36C9 /* UIImageView+HighlightedWebCache.m in Sources */, 80377E991F2F66D400F89830 /* buffer_dec.c in Sources */, 80377C201F2F666300F89830 /* quant_levels_dec_utils.c in Sources */, + 32F7C07F2030719600873181 /* UIImage+Transform.m in Sources */, 80377D471F2F66A700F89830 /* lossless_enc_sse2.c in Sources */, 80377C1E1F2F666300F89830 /* huffman_utils.c in Sources */, ); @@ -3164,6 +3212,7 @@ 3237F9EA20161AE000A88143 /* NSImage+Additions.m in Sources */, 431BB6B61D06D2C1006A3455 /* UIImage+WebP.m in Sources */, 80377E251F2F66A800F89830 /* rescaler_neon.c in Sources */, + 32F7C0792030114C00873181 /* SDWebImageTransformer.m in Sources */, 80377E241F2F66A800F89830 /* rescaler_msa.c in Sources */, 80377E2D1F2F66A800F89830 /* yuv_mips_dsp_r2.c in Sources */, 431BB6B91D06D2C1006A3455 /* UIButton+WebCache.m in Sources */, @@ -3204,6 +3253,7 @@ 80377C6E1F2F666400F89830 /* quant_levels_dec_utils.c in Sources */, 80377EC91F2F66D500F89830 /* buffer_dec.c in Sources */, 80377C6C1F2F666400F89830 /* huffman_utils.c in Sources */, + 32F7C0822030719600873181 /* UIImage+Transform.m in Sources */, 80377E161F2F66A800F89830 /* lossless_enc_sse2.c in Sources */, 431BB6C71D06D2C1006A3455 /* UIImageView+HighlightedWebCache.m in Sources */, ); @@ -3348,6 +3398,7 @@ 32C0FDEC2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 80377E5E1F2F66A800F89830 /* lossless_mips_dsp_r2.c in Sources */, 80377E3D1F2F66A800F89830 /* cost_sse2.c in Sources */, + 32F7C0832030719600873181 /* UIImage+Transform.m in Sources */, 321E60BB1F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 80377E3C1F2F66A800F89830 /* cost_mips32.c in Sources */, 80377E421F2F66A800F89830 /* dec_mips32.c in Sources */, @@ -3355,6 +3406,7 @@ 323F8B851F38EF770092B609 /* histogram_enc.c in Sources */, 80377EE51F2F66D500F89830 /* webp_dec.c in Sources */, 4397D2B01D0DDD8C00BB2784 /* SDImageCache.m in Sources */, + 32F7C07A2030114C00873181 /* SDWebImageTransformer.m in Sources */, 80377E4F1F2F66A800F89830 /* enc_sse41.c in Sources */, 80377E701F2F66A800F89830 /* upsampling_sse2.c in Sources */, ); @@ -3395,6 +3447,7 @@ 80377D6A1F2F66A700F89830 /* argb.c in Sources */, 323F8B7C1F38EF770092B609 /* frame_enc.c in Sources */, 80377EAB1F2F66D400F89830 /* frame_dec.c in Sources */, + 32F7C0772030114C00873181 /* SDWebImageTransformer.m in Sources */, 43C8929D1D9D6DD90022038D /* anim_decode.c in Sources */, 323F8B6A1F38EF770092B609 /* delta_palettization_enc.c in Sources */, 43CE75D41CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */, @@ -3427,6 +3480,7 @@ 4A2CAE1E1AB4BB6800B6BC39 /* SDWebImageDownloaderOperation.m in Sources */, 80377EAD1F2F66D400F89830 /* io_dec.c in Sources */, 80377EAC1F2F66D400F89830 /* idec_dec.c in Sources */, + 32F7C0802030719600873181 /* UIImage+Transform.m in Sources */, 323F8B981F38EF770092B609 /* near_lossless_enc.c in Sources */, 80377D6F1F2F66A700F89830 /* cost.c in Sources */, 80377EB31F2F66D400F89830 /* vp8l_dec.c in Sources */, @@ -3547,6 +3601,7 @@ 323F8B7A1F38EF770092B609 /* frame_enc.c in Sources */, 80377E8B1F2F66D000F89830 /* frame_dec.c in Sources */, 43C8929A1D9D6DD70022038D /* anim_decode.c in Sources */, + 32F7C0752030114C00873181 /* SDWebImageTransformer.m in Sources */, 323F8B681F38EF770092B609 /* delta_palettization_enc.c in Sources */, 43CE75D31CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */, 323F8B5C1F38EF770092B609 /* cost_enc.c in Sources */, @@ -3579,6 +3634,7 @@ 80377E8D1F2F66D000F89830 /* io_dec.c in Sources */, 80377E8C1F2F66D000F89830 /* idec_dec.c in Sources */, 323F8B961F38EF770092B609 /* near_lossless_enc.c in Sources */, + 32F7C07E2030719600873181 /* UIImage+Transform.m in Sources */, 80377CE51F2F66A100F89830 /* cost.c in Sources */, 80377E931F2F66D000F89830 /* vp8l_dec.c in Sources */, 321E609A1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */, diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index adbc64d2..87142799 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -59,6 +59,9 @@ #ifndef UIView #define UIView NSView #endif + #ifndef UIColor + #define UIColor NSColor + #endif #else #if __IPHONE_OS_VERSION_MIN_REQUIRED != 20000 && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0 #error SDWebImage doesn't support Deployment Target version < 5.0 diff --git a/SDWebImage/SDWebImageTransformer.h b/SDWebImage/SDWebImageTransformer.h new file mode 100644 index 00000000..d54bff24 --- /dev/null +++ b/SDWebImage/SDWebImageTransformer.h @@ -0,0 +1,139 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import "UIImage+Transform.h" + +/** + A transformer protocol to transform the image load from cache or from download. + For cache, it store the transformed image to memory cache if the memory cache missed (Default). + For download, it store the transformed image to disk cache and memory cache if the download finished (Default). + + @note The transform process is called from a global queue in order to not to block the main queue. + */ +@protocol SDWebImageTransformer + +@required +/** + For each transformer, it must contains its cache key to used to store the image cache or query from the cache. This key will be appened after the original cache key generated by URL or from user. + + @return The cache key to appended after the original cache key. Should not be nil. + */ +- (nonnull NSString *)transformerKey; + +/** + Transform the image to another image. + + @param image The image to be transformed + @param key The cache key associated to the image + @return The transformed image, or nil if transform failed + */ +- (nullable UIImage *)transformedImageWithImage:(nonnull UIImage *)image forKey:(nonnull NSString *)key; + +@end + +#pragma mark - Pipeline + +// Pipeline transformer. Which you can bind multiple transformers together to let the image to be transformed one by one and generate the final image. +@interface SDWebImagePipelineTransformer : NSObject + +@property (nonatomic, copy, readonly, nonnull) NSArray> *transformers; + +- (nonnull instancetype)initWithTransformers:(nonnull NSArray> *)transformers; + +- (void)addTransformer:(nonnull id)transformer; +- (void)removeTransformer:(nonnull id)transformer; + +@end + +// There are some build-in transformer based on the `UIImage+Transformer` category to provide the common image geometry, image blending and image effect process. Those transform are useful for static image only but you can create your own to support animated image as well. +#pragma mark - Image Geometry + +// Image round corner transformer +@interface SDWebImageRoundCornerTransformer: NSObject + +@property (nonatomic, assign, readonly) CGFloat cornerRadius; +@property (nonatomic, assign, readonly) SDRectCorner corners; +@property (nonatomic, assign, readonly) CGFloat borderWidth; +@property (nonatomic, strong, readonly, nullable) UIColor *borderColor; + +- (nonnull instancetype)initWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(nullable UIColor *)borderColor; + +@end + +// Image resizing transformer +@interface SDWebImageResizingTransformer : NSObject + +@property (nonatomic, assign, readonly) CGSize size; +@property (nonatomic, assign, readonly) SDImageScaleMode scaleMode; + +- (nonnull instancetype)initWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode; + +@end + +// Image cropping transformer +@interface SDWebImageCroppingTransformer : NSObject + +@property (nonatomic, assign, readonly) CGRect rect; + +- (nonnull instancetype)initWithRect:(CGRect)rect; + +@end + +// Image flipping transformer +@interface SDWebImageFlippingTransformer : NSObject + +@property (nonatomic, assign, readonly) BOOL horizontal; +@property (nonatomic, assign, readonly) BOOL vertical; + +- (nonnull instancetype)initWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical; + +@end + +// Image rotation transformer +@interface SDWebImageRotationTransformer : NSObject + +@property (nonatomic, assign, readonly) CGFloat angle; +@property (nonatomic, assign, readonly) BOOL fitSize; + +- (nonnull instancetype)initWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize; + +@end + +#pragma mark - Image Blending + +// Image tint color transformer +@interface SDWebImageTintTransformer : NSObject + +@property (nonatomic, strong, readonly, nonnull) UIColor *tintColor; + +- (nonnull instancetype)initWithColor:(nonnull UIColor *)tintColor; + +@end + +#pragma mark - Image Effect + +// Image blur effect transformer +@interface SDWebImageBlurTransformer : NSObject + +@property (nonatomic, assign, readonly) CGFloat blurRadius; + +- (nonnull instancetype)initWithRadius:(CGFloat)blurRadius; + +@end + +#if SD_UIKIT || SD_MAC +// Core Image filter transformer +@interface SDWebImageFilterTransformer: NSObject + +@property (nonatomic, strong, readonly, nonnull) CIFilter *filter; + +- (nonnull instancetype)initWithFilter:(nonnull CIFilter *)filter; + +@end +#endif diff --git a/SDWebImage/SDWebImageTransformer.m b/SDWebImage/SDWebImageTransformer.m new file mode 100644 index 00000000..0c68e9be --- /dev/null +++ b/SDWebImage/SDWebImageTransformer.m @@ -0,0 +1,309 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageTransformer.h" +#if SD_UIKIT || SD_MAC +#import +#endif + +@interface UIColor (Additions) + +@property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString; + +@end + +@implementation UIColor (Additions) + +- (NSString *)sd_hexString { + CGFloat red, green, blue, alpha; +#if SD_UIKIT + if (![self getRed:&red green:&green blue:&blue alpha:&alpha]) { + [self getWhite:&red alpha:&alpha]; + green = red; + blue = red; + } +#else + @try { + [self getRed:&red green:&green blue:&blue alpha:&alpha]; + } + @catch (NSException *exception) { + [self getWhite:&red alpha:&alpha]; + green = red; + blue = red; + } +#endif + + red = roundf(red * 255.f); + green = roundf(green * 255.f); + blue = roundf(blue * 255.f); + alpha = roundf(alpha * 255.f); + + uint hex = ((uint)alpha << 24) | ((uint)red << 16) | ((uint)green << 8) | ((uint)blue); + + return [NSString stringWithFormat:@"0x%08x", hex]; +} + +@end + +@interface SDWebImagePipelineTransformer () + +@property (nonatomic, copy, readwrite, nonnull) NSArray> *transformers; +@property (nonatomic, copy, readwrite) NSString *transformerKey; + +@end + +@implementation SDWebImagePipelineTransformer + +- (instancetype)initWithTransformers:(NSArray> *)transformers { + self = [super init]; + if (self) { + _transformers = [transformers copy]; + _transformerKey = [[self class] cacheKeyForTransformers:transformers]; + } + return self; +} + ++ (NSString *)cacheKeyForTransformers:(NSArray> *)transformers { + if (transformers.count == 0) { + return @""; + } + NSMutableArray *cacheKeys = [NSMutableArray arrayWithCapacity:transformers.count]; + [transformers enumerateObjectsUsingBlock:^(id _Nonnull transformer, NSUInteger idx, BOOL * _Nonnull stop) { + NSString *cacheKey = transformer.transformerKey; + [cacheKeys addObject:cacheKey]; + }]; + + return [cacheKeys componentsJoinedByString:@"@"]; +} + +- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { + if (!image) { + return nil; + } + UIImage *transformedImage = image; + for (id transformer in self.transformers) { + transformedImage = [transformer transformedImageWithImage:transformedImage forKey:key]; + } + return transformedImage; +} + +- (void)addTransformer:(id)transformer { + if (!transformer) { + return; + } + self.transformers = [self.transformers arrayByAddingObject:transformer]; +} + +- (void)removeTransformer:(id)transformer { + if (!transformer) { + return; + } + NSMutableArray> *transformers = [self.transformers mutableCopy]; + [transformers removeObject:transformer]; + self.transformers = [transformers copy]; +} + +@end + +@implementation SDWebImageRoundCornerTransformer + +- (instancetype)initWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(nullable UIColor *)borderColor { + self = [super init]; + if (self) { + _cornerRadius = cornerRadius; + _corners = corners; + _borderWidth = borderWidth; + _borderColor = borderColor; + } + return self; +} + +- (NSString *)transformerKey { + return [NSString stringWithFormat:@"SDWebImageRoundCornerTransformer(%f,%lu,%f,%@)", self.cornerRadius, (unsigned long)self.corners, self.borderWidth, self.borderColor.sd_hexString]; +} + +- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { + if (!image) { + return nil; + } + return [image sd_roundedCornerImageWithRadius:self.cornerRadius corners:self.corners borderWidth:self.borderWidth borderColor:self.borderColor]; +} + +@end + +@implementation SDWebImageResizingTransformer + +- (instancetype)initWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode { + self = [super init]; + if (self) { + _size = size; + _scaleMode = scaleMode; + } + return self; +} + +- (NSString *)transformerKey { + CGSize size = self.size; + return [NSString stringWithFormat:@"SDWebImageResizingTransformer({%f,%f},%lu)", size.width, size.height, (unsigned long)self.scaleMode]; +} + +- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { + if (!image) { + return nil; + } + return [image sd_resizedImageWithSize:self.size scaleMode:self.scaleMode]; +} + +@end + +@implementation SDWebImageCroppingTransformer + +- (instancetype)initWithRect:(CGRect)rect { + self = [super init]; + if (self) { + _rect = rect; + } + return self; +} + +- (NSString *)transformerKey { + CGRect rect = self.rect; + return [NSString stringWithFormat:@"SDWebImageCroppingTransformer({%f,%f,%f,%f})", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height]; +} + +- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { + if (!image) { + return nil; + } + return [image sd_croppedImageWithRect:self.rect]; +} + +@end + +@implementation SDWebImageFlippingTransformer + +- (instancetype)initWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical { + self = [super init]; + if (self) { + _horizontal = horizontal; + _vertical = vertical; + } + return self; +} + +- (NSString *)transformerKey { + return [NSString stringWithFormat:@"SDWebImageFlippingTransformer(%d,%d)", self.horizontal, self.vertical]; +} + +- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { + if (!image) { + return nil; + } + return [image sd_flippedImageWithHorizontal:self.horizontal vertical:self.vertical]; +} + +@end + +@implementation SDWebImageRotationTransformer + +- (instancetype)initWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize { + self = [super init]; + if (self) { + _angle = angle; + _fitSize = fitSize; + } + return self; +} + +- (NSString *)transformerKey { + return [NSString stringWithFormat:@"SDWebImageRotationTransformer(%f,%d)", self.angle, self.fitSize]; +} + +- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { + if (!image) { + return nil; + } + return [image sd_rotatedImageWithAngle:self.angle fitSize:self.fitSize]; +} + +@end + +#pragma mark - Image Blending + +@implementation SDWebImageTintTransformer + +- (instancetype)initWithColor:(UIColor *)tintColor { + self = [super init]; + if (self) { + _tintColor = tintColor; + } + return self; +} + +- (NSString *)transformerKey { + return [NSString stringWithFormat:@"SDWebImageTintTransformer(%@)", self.tintColor.sd_hexString]; +} + +- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { + if (!image) { + return nil; + } + return [image sd_tintedImageWithColor:self.tintColor]; +} + +@end + +#pragma mark - Image Effect + +@implementation SDWebImageBlurTransformer + +- (instancetype)initWithRadius:(CGFloat)blurRadius { + self = [super init]; + if (self) { + _blurRadius = blurRadius; + } + return self; +} + +- (NSString *)transformerKey { + return [NSString stringWithFormat:@"SDWebImageBlurTransformer(%f)", self.blurRadius]; +} + +- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { + if (!image) { + return nil; + } + return [image sd_blurredImageWithRadius:self.blurRadius]; +} + +@end + +#if SD_UIKIT || SD_MAC +@implementation SDWebImageFilterTransformer + +- (instancetype)initWithFilter:(CIFilter *)filter { + self = [super init]; + if (self) { + _filter = filter; + } + return self; +} + +- (NSString *)transformerKey { + return [NSString stringWithFormat:@"SDWebImageFilterTransformer(%@)", self.filter.name]; +} + +- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { + if (!image) { + return nil; + } + return [image sd_filteredImageWithFilter:self.filter]; +} + +@end +#endif diff --git a/SDWebImage/UIImage+Transform.h b/SDWebImage/UIImage+Transform.h new file mode 100644 index 00000000..73b0c5c5 --- /dev/null +++ b/SDWebImage/UIImage+Transform.h @@ -0,0 +1,126 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +typedef NS_ENUM(NSUInteger, SDImageScaleMode) { + SDImageScaleModeFill = 0, + SDImageScaleModeAspectFit = 1, + SDImageScaleModeAspectFill = 2 +}; + +#if SD_UIKIT || SD_WATCH +typedef UIRectCorner SDRectCorner; +#else +typedef NS_OPTIONS(NSUInteger, SDRectCorner) { + SDRectCornerTopLeft = 1 << 0, + SDRectCornerTopRight = 1 << 1, + SDRectCornerBottomLeft = 1 << 2, + SDRectCornerBottomRight = 1 << 3, + SDRectCornerAllCorners = ~0UL +}; +#endif + +/** + Provide some commen method for `UIImage`. + Image process is based on Core Graphics and vImage. + */ +@interface UIImage (Transform) + +#pragma mark - Image Geometry + +/** + Returns a new image which is scaled from this image. + The image content will be changed with the scale mode. + + @param size The new size to be scaled, values should be positive. + @param contentMode The scale mode for image content. + @return The new image with the given size. + */ +- (nullable UIImage *)sd_resizedImageWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode; + +/** + Returns a new image which is cropped from this image. + + @param cropRect Image's inner rect. + @return The new image with the cropping rect. + */ +- (nullable UIImage *)sd_croppedImageWithRect:(CGRect)rect; + +/** + Rounds a new image with a given corner radius and corners. + + @param cornerRadius The radius of each corner oval. Values larger than half the + rectangle's width or height are clamped appropriately to + half the width or height. + @param corners A bitmask value that identifies the corners that you want + rounded. You can use this parameter to round only a subset + of the corners of the rectangle. + @param borderWidth The inset border line width. Values larger than half the rectangle's + width or height are clamped appropriately to half the width + or height. + @param borderColor The border stroke color. nil means clear color. + @return The new image with the round corner. + */ +- (nullable UIImage *)sd_roundedCornerImageWithRadius:(CGFloat)cornerRadius + corners:(SDRectCorner)corners + borderWidth:(CGFloat)borderWidth + borderColor:(nullable UIColor *)borderColor; + +/** + Returns a new rotated image (relative to the center). + + @param radians Rotated radians in counterclockwise.⟲ + @param fitSize YES: new image's size is extend to fit all content. + NO: image's size will not change, content may be clipped. + @return The new image with the rotation. + */ +- (nullable UIImage *)sd_rotatedImageWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize; + +/** + Returns a new horizontally(vertically) flipped image. + + @param horizontal YES to flip the image horizontally. ⇋ + @param vertical YES to flip the image vertically. ⥯ + @return The new image with the flipping. + */ +- (nullable UIImage *)sd_flippedImageWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical; + +#pragma mark - Image Blending + +/** + Return a tinted image in alpha channel with the given color. + + @param tintColor The color. + @return The new image with the tint color. + */ +- (nullable UIImage *)sd_tintedImageWithColor:(nonnull UIColor *)tintColor; + +#pragma mark - Image Effect + +/** + Return a new image applied a blur effect. + + @param blurRadius The radius of the blur in points, 0 means no blur effect. + + @return The new image with blur effect, or nil if an error occurs (e.g. no enough memory). + */ +- (nullable UIImage *)sd_blurredImageWithRadius:(CGFloat)blurRadius; + +#if SD_UIKIT || SD_MAC +/** + Return a new image applied a CIFilter. + + @param filter The CIFilter to be applied to the image. + @return The new image with the CIFilter, or nil if an error occurs (e.g. no + enough memory). + */ +- (nullable UIImage *)sd_filteredImageWithFilter:(nonnull CIFilter *)filter; +#endif + +@end diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m new file mode 100644 index 00000000..79f16094 --- /dev/null +++ b/SDWebImage/UIImage+Transform.m @@ -0,0 +1,505 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIImage+Transform.h" +#import "NSImage+Additions.h" +#import +#if SD_UIKIT || SD_MAC +#import +#endif + +#ifndef SD_SWAP // swap two value +#define SD_SWAP(_a_, _b_) do { __typeof__(_a_) _tmp_ = (_a_); (_a_) = (_b_); (_b_) = _tmp_; } while (0) +#endif + +#if SD_MAC +static CGContextRef SDCGContextCreateARGBBitmapContext(CGSize size, BOOL opaque, CGFloat scale) { + size_t width = ceil(size.width * scale); + size_t height = ceil(size.height * scale); + if (width < 1 || height < 1) return NULL; + + //pre-multiplied ARGB, 8-bits per component + CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); + CGImageAlphaInfo alphaInfo = (opaque ? kCGImageAlphaNoneSkipFirst : kCGImageAlphaPremultipliedFirst); + CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, space, kCGBitmapByteOrderDefault | alphaInfo); + CGColorSpaceRelease(space); + return context; +} +#endif + +static void SDGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale) { +#if SD_UIKIT || SD_WATCH + UIGraphicsBeginImageContextWithOptions(size, opaque, scale); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextTranslateCTM(context, 0, -size.height); + CGContextScaleCTM(context, scale, -scale); +#else + CGContextRef context = SDCGContextCreateARGBBitmapContext(size, opaque, scale); + if (!context) { + return; + } + NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithCGContext:context flipped:NO]; + CGContextRelease(context); + [NSGraphicsContext saveGraphicsState]; + NSGraphicsContext.currentContext = graphicsContext; +#endif +} + +static CGContextRef SDGraphicsGetCurrentContext(void) { +#if SD_UIKIT || SD_WATCH + return UIGraphicsGetCurrentContext(); +#else + return NSGraphicsContext.currentContext.CGContext; +#endif +} + +static void SDGraphicsEndImageContext(void) { +#if SD_UIKIT || SD_WATCH + UIGraphicsEndImageContext(); +#else + [NSGraphicsContext restoreGraphicsState]; +#endif +} + +static UIImage * SDGraphicsGetImageFromCurrentImageContext(void) { +#if SD_UIKIT || SD_WATCH + return UIGraphicsGetImageFromCurrentImageContext(); +#else + CGContextRef context = SDGraphicsGetCurrentContext(); + if (!context) { + return nil; + } + CGImageRef imageRef = CGBitmapContextCreateImage(context); + if (!imageRef) { + return nil; + } + NSImage *image = [[NSImage alloc] initWithCGImage:imageRef size:NSZeroSize]; + CGImageRelease(imageRef); + return image; +#endif +} + +static SDRectCorner SDRectCornerConvertCounterClockwise(SDRectCorner corners) { +#if SD_UIKIT || SD_WATCH + if (corners != UIRectCornerAllCorners) { + UIRectCorner tmp = 0; + if (corners & UIRectCornerTopLeft) tmp |= UIRectCornerBottomLeft; + if (corners & UIRectCornerTopRight) tmp |= UIRectCornerBottomRight; + if (corners & UIRectCornerBottomLeft) tmp |= UIRectCornerTopLeft; + if (corners & UIRectCornerBottomRight) tmp |= UIRectCornerTopRight; + corners = tmp; + } +#else + if (corners != SDRectCornerAllCorners) { + SDRectCorner tmp = 0; + if (corners & SDRectCornerTopLeft) tmp |= SDRectCornerBottomLeft; + if (corners & SDRectCornerTopRight) tmp |= SDRectCornerBottomRight; + if (corners & SDRectCornerBottomLeft) tmp |= SDRectCornerTopLeft; + if (corners & SDRectCornerBottomRight) tmp |= SDRectCornerTopRight; + corners = tmp; + } +#endif + return corners; +} + +static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMode scaleMode) { + rect = CGRectStandardize(rect); + size.width = size.width < 0 ? -size.width : size.width; + size.height = size.height < 0 ? -size.height : size.height; + CGPoint center = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect)); + switch (scaleMode) { + case SDImageScaleModeAspectFit: + case SDImageScaleModeAspectFill: { + if (rect.size.width < 0.01 || rect.size.height < 0.01 || + size.width < 0.01 || size.height < 0.01) { + rect.origin = center; + rect.size = CGSizeZero; + } else { + CGFloat scale; + if (scaleMode == SDImageScaleModeAspectFit) { + if (size.width / size.height < rect.size.width / rect.size.height) { + scale = rect.size.height / size.height; + } else { + scale = rect.size.width / size.width; + } + } else { + if (size.width / size.height < rect.size.width / rect.size.height) { + scale = rect.size.width / size.width; + } else { + scale = rect.size.height / size.height; + } + } + size.width *= scale; + size.height *= scale; + rect.size = size; + rect.origin = CGPointMake(center.x - size.width * 0.5, center.y - size.height * 0.5); + } + } break; + case SDImageScaleModeFill: + default: { + rect = rect; + } + } + return rect; +} + +#if SD_MAC +@interface NSBezierPath (Compatibility) + ++ (instancetype)bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius; + +@end + +@implementation NSBezierPath (Compatibility) + ++ (instancetype)bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius { + NSBezierPath *path = [NSBezierPath bezierPath]; + + CGFloat maxCorner = MIN(NSWidth(rect), NSHeight(rect)) / 2; + + CGFloat topLeftRadius = MIN(maxCorner, (corners & SDRectCornerTopLeft) ? cornerRadius : 0); + CGFloat topRightRadius = MIN(maxCorner, (corners & SDRectCornerTopRight) ? cornerRadius : 0); + CGFloat bottomLeftRadius = MIN(maxCorner, (corners & SDRectCornerBottomLeft) ? cornerRadius : 0); + CGFloat bottomRightRadius = MIN(maxCorner, (corners & SDRectCornerBottomRight) ? cornerRadius : 0); + + NSPoint topLeft = NSMakePoint(NSMinX(rect), NSMaxY(rect)); + NSPoint topRight = NSMakePoint(NSMaxX(rect), NSMaxY(rect)); + NSPoint bottomLeft = NSMakePoint(NSMinX(rect), NSMinY(rect)); + NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect)); + + [path moveToPoint:NSMakePoint(NSMidX(rect), NSMaxY(rect))]; + [path appendBezierPathWithArcFromPoint:topLeft toPoint:bottomLeft radius:topLeftRadius]; + [path appendBezierPathWithArcFromPoint:bottomLeft toPoint:bottomRight radius:bottomLeftRadius]; + [path appendBezierPathWithArcFromPoint:bottomRight toPoint:topRight radius:bottomRightRadius]; + [path appendBezierPathWithArcFromPoint:topRight toPoint:topLeft radius:topRightRadius]; + [path closePath]; + + return path; +} + +@end + +#endif + +@implementation UIImage (Transform) + +- (void)sd_drawInRect:(CGRect)rect withScaleMode:(SDImageScaleMode)scaleMode clipsToBounds:(BOOL)clips { + CGRect drawRect = SDCGRectFitWithScaleMode(rect, self.size, scaleMode); + if (drawRect.size.width == 0 || drawRect.size.height == 0) return; + if (clips) { + CGContextRef context = SDGraphicsGetCurrentContext(); + if (context) { + CGContextSaveGState(context); + CGContextAddRect(context, rect); + CGContextClip(context); + [self drawInRect:drawRect]; + CGContextRestoreGState(context); + } + } else { + [self drawInRect:drawRect]; + } +} + +- (UIImage *)sd_resizedImageWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode { + if (size.width <= 0 || size.height <= 0) return nil; + SDGraphicsBeginImageContextWithOptions(size, NO, self.scale); + [self sd_drawInRect:CGRectMake(0, 0, size.width, size.height) withScaleMode:scaleMode clipsToBounds:NO]; + UIImage *image = SDGraphicsGetImageFromCurrentImageContext(); + SDGraphicsEndImageContext(); + return image; +} + +- (UIImage *)sd_croppedImageWithRect:(CGRect)rect { + if (!self.CGImage) return nil; + rect.origin.x *= self.scale; + rect.origin.y *= self.scale; + rect.size.width *= self.scale; + rect.size.height *= self.scale; + if (rect.size.width <= 0 || rect.size.height <= 0) return nil; + CGImageRef imageRef = CGImageCreateWithImageInRect(self.CGImage, rect); + if (!imageRef) { + return nil; + } +#if SD_UIKIT || SD_WATCH + UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation]; +#else + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale]; +#endif + CGImageRelease(imageRef); + return image; +} + +- (UIImage *)sd_roundedCornerImageWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor { + if (!self.CGImage) return nil; + corners = SDRectCornerConvertCounterClockwise(corners); + SDGraphicsBeginImageContextWithOptions(self.size, NO, self.scale); + CGContextRef context = SDGraphicsGetCurrentContext(); + CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height); + + CGFloat minSize = MIN(self.size.width, self.size.height); + if (borderWidth < minSize / 2) { +#if SD_UIKIT || SD_WATCH + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth) byRoundingCorners:corners cornerRadii:CGSizeMake(cornerRadius, cornerRadius)]; +#else + NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth) byRoundingCorners:corners cornerRadius:cornerRadius]; +#endif + [path closePath]; + + CGContextSaveGState(context); + [path addClip]; + CGContextDrawImage(context, rect, self.CGImage); + CGContextRestoreGState(context); + } + + if (borderColor && borderWidth < minSize / 2 && borderWidth > 0) { + CGFloat strokeInset = (floor(borderWidth * self.scale) + 0.5) / self.scale; + CGRect strokeRect = CGRectInset(rect, strokeInset, strokeInset); + CGFloat strokeRadius = cornerRadius > self.scale / 2 ? cornerRadius - self.scale / 2 : 0; +#if SD_UIKIT || SD_WATCH + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:strokeRect byRoundingCorners:corners cornerRadii:CGSizeMake(strokeRadius, strokeRadius)]; +#else + NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:strokeRect byRoundingCorners:corners cornerRadius:strokeRadius]; +#endif + [path closePath]; + + path.lineWidth = borderWidth; + [borderColor setStroke]; + [path stroke]; + } + + UIImage *image = SDGraphicsGetImageFromCurrentImageContext(); + SDGraphicsEndImageContext(); + return image; +} + +- (UIImage *)sd_rotatedImageWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize { + if (!self.CGImage) return nil; + size_t width = (size_t)CGImageGetWidth(self.CGImage); + size_t height = (size_t)CGImageGetHeight(self.CGImage); + CGRect newRect = CGRectApplyAffineTransform(CGRectMake(0., 0., width, height), + fitSize ? CGAffineTransformMakeRotation(angle) : CGAffineTransformIdentity); + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate(NULL, + (size_t)newRect.size.width, + (size_t)newRect.size.height, + 8, + (size_t)newRect.size.width * 4, + colorSpace, + kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst); + CGColorSpaceRelease(colorSpace); + if (!context) return nil; + + CGContextSetShouldAntialias(context, true); + CGContextSetAllowsAntialiasing(context, true); + CGContextSetInterpolationQuality(context, kCGInterpolationHigh); + + CGContextTranslateCTM(context, +(newRect.size.width * 0.5), +(newRect.size.height * 0.5)); + CGContextRotateCTM(context, angle); + + CGContextDrawImage(context, CGRectMake(-(width * 0.5), -(height * 0.5), width, height), self.CGImage); + CGImageRef imgRef = CGBitmapContextCreateImage(context); +#if SD_UIKIT || SD_WATCH + UIImage *img = [UIImage imageWithCGImage:imgRef scale:self.scale orientation:self.imageOrientation]; +#else + UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale]; +#endif + CGImageRelease(imgRef); + CGContextRelease(context); + return img; +} + +- (UIImage *)sd_flippedImageWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical { + if (!self.CGImage) return nil; + size_t width = (size_t)CGImageGetWidth(self.CGImage); + size_t height = (size_t)CGImageGetHeight(self.CGImage); + size_t bytesPerRow = width * 4; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst); + CGColorSpaceRelease(colorSpace); + if (!context) return nil; + + CGContextDrawImage(context, CGRectMake(0, 0, width, height), self.CGImage); + UInt8 *data = (UInt8 *)CGBitmapContextGetData(context); + if (!data) { + CGContextRelease(context); + return nil; + } + vImage_Buffer src = { data, height, width, bytesPerRow }; + vImage_Buffer dest = { data, height, width, bytesPerRow }; + if (vertical) { + vImageVerticalReflect_ARGB8888(&src, &dest, kvImageBackgroundColorFill); + } + if (horizontal) { + vImageHorizontalReflect_ARGB8888(&src, &dest, kvImageBackgroundColorFill); + } + CGImageRef imgRef = CGBitmapContextCreateImage(context); + CGContextRelease(context); +#if SD_UIKIT || SD_WATCH + UIImage *img = [UIImage imageWithCGImage:imgRef scale:self.scale orientation:self.imageOrientation]; +#else + UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale]; +#endif + CGImageRelease(imgRef); + return img; +} + +#pragma mark - Image Blending + +- (UIImage *)sd_tintedImageWithColor:(UIColor *)tintColor { + if (!self.CGImage) return nil; + if (!tintColor.CGColor) return nil; + + BOOL hasTint = CGColorGetAlpha(tintColor.CGColor) > __FLT_EPSILON__; + if (!hasTint) { +#if SD_UIKIT || SD_WATCH + return [UIImage imageWithCGImage:self.CGImage scale:self.scale orientation:self.imageOrientation]; +#else + return [[UIImage alloc] initWithCGImage:self.CGImage scale:self.scale]; +#endif + } + + CGSize size = self.size; + CGRect rect = { CGPointZero, size }; + CGFloat scale = self.scale; + + // blend mode, see https://en.wikipedia.org/wiki/Alpha_compositing + CGBlendMode blendMode = kCGBlendModeSourceAtop; + + SDGraphicsBeginImageContextWithOptions(size, NO, scale); + CGContextRef context = SDGraphicsGetCurrentContext(); + CGContextDrawImage(context, rect, self.CGImage); + CGContextSetBlendMode(context, blendMode); + CGContextSetFillColorWithColor(context, tintColor.CGColor); + CGContextFillRect(context, rect); + UIImage *image = SDGraphicsGetImageFromCurrentImageContext(); + SDGraphicsEndImageContext(); + + return image; +} + +#pragma mark - Image Effect + +- (UIImage *)sd_blurredImageWithRadius:(CGFloat)blurRadius { + if (self.size.width < 1 || self.size.height < 1) { + return nil; + } + if (!self.CGImage) { + return nil; + } + + BOOL hasBlur = blurRadius > __FLT_EPSILON__; + if (!hasBlur) { + return self; + } + + CGFloat scale = self.scale; + CGImageRef imageRef = self.CGImage; + + vImage_Buffer effect = {}, scratch = {}; + vImage_Buffer *input = NULL, *output = NULL; + + vImage_CGImageFormat format = { + .bitsPerComponent = 8, + .bitsPerPixel = 32, + .colorSpace = NULL, + .bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little, //requests a BGRA buffer. + .version = 0, + .decode = NULL, + .renderingIntent = kCGRenderingIntentDefault + }; + + vImage_Error err; + err = vImageBuffer_InitWithCGImage(&effect, &format, NULL, imageRef, kvImagePrintDiagnosticsToConsole); + if (err != kvImageNoError) { + NSLog(@"UIImage+Transform error: vImageBuffer_InitWithCGImage returned error code %zi for inputImage: %@", err, self); + return nil; + } + err = vImageBuffer_Init(&scratch, effect.height, effect.width, format.bitsPerPixel, kvImageNoFlags); + if (err != kvImageNoError) { + NSLog(@"UIImage+Transform error: vImageBuffer_Init returned error code %zi for inputImage: %@", err, self); + return nil; + } + + input = &effect; + output = &scratch; + + if (hasBlur) { + // A description of how to compute the box kernel width from the Gaussian + // radius (aka standard deviation) appears in the SVG spec: + // http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement + // + // For larger values of 's' (s >= 2.0), an approximation can be used: Three + // successive box-blurs build a piece-wise quadratic convolution kernel, which + // approximates the Gaussian kernel to within roughly 3%. + // + // let d = floor(s * 3*sqrt(2*pi)/4 + 0.5) + // + // ... if d is odd, use three box-blurs of size 'd', centered on the output pixel. + // + CGFloat inputRadius = blurRadius * scale; + if (inputRadius - 2.0 < __FLT_EPSILON__) inputRadius = 2.0; + uint32_t radius = floor((inputRadius * 3.0 * sqrt(2 * M_PI) / 4 + 0.5) / 2); + radius |= 1; // force radius to be odd so that the three box-blur methodology works. + int iterations; + if (blurRadius * scale < 0.5) iterations = 1; + else if (blurRadius * scale < 1.5) iterations = 2; + else iterations = 3; + NSInteger tempSize = vImageBoxConvolve_ARGB8888(input, output, NULL, 0, 0, radius, radius, NULL, kvImageGetTempBufferSize | kvImageEdgeExtend); + void *temp = malloc(tempSize); + for (int i = 0; i < iterations; i++) { + vImageBoxConvolve_ARGB8888(input, output, temp, 0, 0, radius, radius, NULL, kvImageEdgeExtend); + SD_SWAP(input, output); + } + free(temp); + } + + CGImageRef effectCGImage = NULL; + effectCGImage = vImageCreateCGImageFromBuffer(input, &format, NULL, NULL, kvImageNoAllocate, NULL); + if (effectCGImage == NULL) { + effectCGImage = vImageCreateCGImageFromBuffer(input, &format, NULL, NULL, kvImageNoFlags, NULL); + free(input->data); + } + free(output->data); +#if SD_UIKIT || SD_WATCH + UIImage *outputImage = [UIImage imageWithCGImage:effectCGImage scale:self.scale orientation:self.imageOrientation]; +#else + UIImage *outputImage = [[UIImage alloc] initWithCGImage:effectCGImage scale:self.scale]; +#endif + CGImageRelease(effectCGImage); + + return outputImage; +} + +#if SD_UIKIT || SD_MAC +- (UIImage *)sd_filteredImageWithFilter:(CIFilter *)filter { + if (!self.CGImage) return nil; + + CIContext *context = [CIContext context]; + CIImage *inputImage = [CIImage imageWithCGImage:self.CGImage]; + if (!inputImage) return nil; + + [filter setValue:inputImage forKey:kCIInputImageKey]; + CIImage *outputImage = filter.outputImage; + if (!outputImage) return nil; + + CGImageRef imageRef = [context createCGImage:outputImage fromRect:outputImage.extent]; + if (!imageRef) return nil; + +#if SD_UIKIT + UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation]; +#else + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale]; +#endif + CGImageRelease(imageRef); + + return image; +} +#endif + +@end From 464d725368baee42ef249e507fa18340595adfe0 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 13 Feb 2018 18:30:25 +0800 Subject: [PATCH 049/361] Adopt the transformer to cache & manager. Use a new context option SDWebImageContextCustomTransformer to bind the transformer Drop old way of delegate method for transformer. Add two new delegate methods to allow advanced use case after we remove that. --- SDWebImage.xcodeproj/project.pbxproj | 12 ++++++------ SDWebImage/SDImageCache.h | 7 ++++++- SDWebImage/SDImageCache.m | 12 ++++++++++-- SDWebImage/SDWebImageDefine.h | 5 +++++ SDWebImage/SDWebImageDefine.m | 1 + SDWebImage/SDWebImageManager.h | 19 +++---------------- SDWebImage/SDWebImageManager.m | 12 ++++++++---- SDWebImage/SDWebImageTransformer.h | 3 +++ SDWebImage/SDWebImageTransformer.m | 4 +++- SDWebImage/UIImage+Transform.h | 6 +++--- SDWebImage/UIImage+Transform.m | 4 ++-- WebImage/SDWebImage.h | 2 ++ 12 files changed, 52 insertions(+), 35 deletions(-) diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 1ff4efb0..7d7389da 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -406,12 +406,12 @@ 32F7C0812030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; 32F7C0822030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; 32F7C0832030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; - 32F7C0842030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; }; - 32F7C0852030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; }; - 32F7C0862030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; }; - 32F7C0872030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; }; - 32F7C0882030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; }; - 32F7C0892030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; }; + 32F7C0842030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0852030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0862030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0872030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0882030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0892030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D1231D0E0E3B004B36C9 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D86148C56230056699D /* SDImageCache.m */; }; 4314D1311D0E0E3B004B36C9 /* SDWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8C148C56230056699D /* SDWebImageDownloader.m */; }; 4314D1341D0E0E3B004B36C9 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB921762547C00698166 /* UIImage+WebP.m */; }; diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 4d51c03b..07dfee44 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -34,7 +34,12 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { /** * By default, we query the memory cache synchronously, disk cache asynchronously. This mask can force to query disk cache synchronously. */ - SDImageCacheQueryDiskSync = 1 << 1 + SDImageCacheQueryDiskSync = 1 << 1, + /** + * We usually don't apply transform on animated images as most transformers could not manage animated images. + * Use this flag to transform them anyway. + */ + SDImageCacheTransformAnimatedImage = 1 << 2, }; typedef void(^SDCacheQueryCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType); diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 68f5f459..a16b4600 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -10,6 +10,7 @@ #import #import "NSImage+Additions.h" #import "SDWebImageCodersManager.h" +#import "SDWebImageTransformer.h" #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); #define UNLOCK(lock) dispatch_semaphore_signal(lock); @@ -532,11 +533,18 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { diskImage = image; cacheType = SDImageCacheTypeMemory; } else if (diskData) { + NSString *cacheKey = key; + if ([context valueForKey:SDWebImageContextCustomTransformer]) { + // grab the transformed disk image if transformer provided + id transformer = [context valueForKey:SDWebImageContextCustomTransformer]; + NSString *transformerKey = [transformer transformerKey]; + cacheKey = [[key stringByAppendingString:SDWebImageTransformerKeySeparator] stringByAppendingString:transformerKey]; + } // decode image data only if in-memory cache missed - diskImage = [self diskImageForKey:key data:diskData]; + diskImage = [self diskImageForKey:cacheKey data:diskData]; if (diskImage && self.config.shouldCacheImagesInMemory) { NSUInteger cost = SDCacheCostForImage(diskImage); - [self.memCache setObject:diskImage forKey:key cost:cost]; + [self.memCache setObject:diskImage forKey:cacheKey cost:cost]; } } diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index d99d22d4..b3f5e726 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -20,3 +20,8 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextSetIma A SDWebImageManager instance to control the image download and cache process using in UIImageView+WebCache category and likes. If not provided, use the shared manager (SDWebImageManager) */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustomManager; + +/** + A id instance which conforms SDWebImageTransformer protocol. It's used for image transform after the image load finished and store the transformed image to cache. (id) + */ +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustomTransformer; diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m index 36adffae..ae88e07f 100644 --- a/SDWebImage/SDWebImageDefine.m +++ b/SDWebImage/SDWebImageDefine.m @@ -10,3 +10,4 @@ SDWebImageContextOption const SDWebImageContextSetImageGroup = @"setImageGroup"; SDWebImageContextOption const SDWebImageContextCustomManager = @"customManager"; +SDWebImageContextOption const SDWebImageContextCustomTransformer = @"customTransformer"; diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 222392d0..baf66ddb 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -76,8 +76,7 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { SDWebImageDelayPlaceholder = 1 << 9, /** - * We usually don't call transformDownloadedImage delegate method on animated images, - * as most transformation code would mangle it. + * We usually don't apply transform on animated images as most transformers could not manage animated images. * Use this flag to transform them anyway. */ SDWebImageTransformAnimatedImage = 1 << 10, @@ -115,7 +114,7 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { /** * By default, when you use `SDWebImageTransition` to do some view transition after the image load finished, this transition is only applied for image download from the network. This mask can force to apply view transition for memory and disk cache as well. */ - SDWebImageForceTransition = 1 << 16 + SDWebImageForceTransition = 1 << 16, }; typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL); @@ -141,7 +140,7 @@ typedef NSData * _Nullable(^SDWebImageCacheSerializerBlock)(UIImage * _Nonnull i * * @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied. */ -- (BOOL)imageManager:(nonnull SDWebImageManager *)imageManager shouldDownloadImageForURL:(nullable NSURL *)imageURL; +- (BOOL)imageManager:(nonnull SDWebImageManager *)imageManager shouldDownloadImageForURL:(nonnull NSURL *)imageURL; /** * Controls the complicated logic to mark as failed URLs when download error occur. @@ -153,18 +152,6 @@ typedef NSData * _Nullable(^SDWebImageCacheSerializerBlock)(UIImage * _Nonnull i */ - (BOOL)imageManager:(nonnull SDWebImageManager *)imageManager shouldBlockFailedURL:(nonnull NSURL *)imageURL withError:(nonnull NSError *)error; -/** - * Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory. - * NOTE: This method is called from a global queue in order to not to block the main thread. - * - * @param imageManager The current `SDWebImageManager` - * @param image The image to transform - * @param imageURL The url of the image to transform - * - * @return The transformed image object. - */ -- (nullable UIImage *)imageManager:(nonnull SDWebImageManager *)imageManager transformDownloadedImage:(nullable UIImage *)image withURL:(nullable NSURL *)imageURL; - @end /** diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index ff5c4017..5e9ae917 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -9,6 +9,7 @@ #import "SDWebImageManager.h" #import "NSImage+Additions.h" #import +#import "SDWebImageTransformer.h" @interface SDWebImageCombinedOperation : NSObject @@ -153,6 +154,7 @@ SDImageCacheOptions cacheOptions = 0; if (options & SDWebImageQueryDataWhenInMemory) cacheOptions |= SDImageCacheQueryDataWhenInMemory; if (options & SDWebImageQueryDiskSync) cacheOptions |= SDImageCacheQueryDiskSync; + if (options & SDWebImageTransformAnimatedImage) cacheOptions |= SDImageCacheTransformAnimatedImage; __weak SDWebImageCombinedOperation *weakOperation = operation; operation.cacheOperation = [self.imageCache queryCacheOperationForKey:key options:cacheOptions done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) { @@ -238,11 +240,13 @@ if (options & SDWebImageRefreshCached && cachedImage && !downloadedImage) { // Image refresh hit the NSURLCache cache, do not call the completion block - } else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) { + } else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [context valueForKey:SDWebImageContextCustomTransformer]) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url]; - + id transformer = [context valueForKey:SDWebImageContextCustomTransformer]; + UIImage *transformedImage = [transformer transformedImageWithImage:downloadedImage forKey:key]; if (transformedImage && finished) { + NSString *transformerKey = [transformer transformerKey]; + NSString *cacheKey = [[key stringByAppendingString:SDWebImageTransformerKeySeparator] stringByAppendingString:transformerKey]; BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage]; NSData *cacheData; // pass nil if the image was transformed, so we can recalculate the data from the image @@ -251,7 +255,7 @@ } else { cacheData = (imageWasTransformed ? nil : downloadedData); } - [self.imageCache storeImage:transformedImage imageData:cacheData forKey:key toDisk:cacheOnDisk completion:nil]; + [self.imageCache storeImage:transformedImage imageData:cacheData forKey:cacheKey toDisk:cacheOnDisk completion:nil]; } [self callCompletionBlockForOperation:strongSubOperation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; diff --git a/SDWebImage/SDWebImageTransformer.h b/SDWebImage/SDWebImageTransformer.h index d54bff24..8080e47f 100644 --- a/SDWebImage/SDWebImageTransformer.h +++ b/SDWebImage/SDWebImageTransformer.h @@ -39,6 +39,9 @@ #pragma mark - Pipeline +// Separator for different transformerKey, for example, `image.png` |> flip(YES,NO) |> rotate(pi/4,YES) => 'image-SDWebImageFlippingTransformer(1,0)-SDWebImageRotationTransformer(0.78539816339,1).png' +FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageTransformerKeySeparator; + // Pipeline transformer. Which you can bind multiple transformers together to let the image to be transformed one by one and generate the final image. @interface SDWebImagePipelineTransformer : NSObject diff --git a/SDWebImage/SDWebImageTransformer.m b/SDWebImage/SDWebImageTransformer.m index 0c68e9be..13da7fed 100644 --- a/SDWebImage/SDWebImageTransformer.m +++ b/SDWebImage/SDWebImageTransformer.m @@ -50,6 +50,8 @@ @end +NSString * const SDWebImageTransformerKeySeparator = @"-"; + @interface SDWebImagePipelineTransformer () @property (nonatomic, copy, readwrite, nonnull) NSArray> *transformers; @@ -78,7 +80,7 @@ [cacheKeys addObject:cacheKey]; }]; - return [cacheKeys componentsJoinedByString:@"@"]; + return [cacheKeys componentsJoinedByString:SDWebImageTransformerKeySeparator]; } - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { diff --git a/SDWebImage/UIImage+Transform.h b/SDWebImage/UIImage+Transform.h index 73b0c5c5..c042977d 100644 --- a/SDWebImage/UIImage+Transform.h +++ b/SDWebImage/UIImage+Transform.h @@ -39,7 +39,7 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { The image content will be changed with the scale mode. @param size The new size to be scaled, values should be positive. - @param contentMode The scale mode for image content. + @param scaleMode The scale mode for image content. @return The new image with the given size. */ - (nullable UIImage *)sd_resizedImageWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode; @@ -47,7 +47,7 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { /** Returns a new image which is cropped from this image. - @param cropRect Image's inner rect. + @param rect Image's inner rect. @return The new image with the cropping rect. */ - (nullable UIImage *)sd_croppedImageWithRect:(CGRect)rect; @@ -75,7 +75,7 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { /** Returns a new rotated image (relative to the center). - @param radians Rotated radians in counterclockwise.⟲ + @param angle Rotated radians in counterclockwise.⟲ @param fitSize YES: new image's size is extend to fit all content. NO: image's size will not change, content may be clipped. @return The new image with the rotation. diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 79f16094..ecacfd09 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -149,13 +149,13 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod } #if SD_MAC -@interface NSBezierPath (Compatibility) +@interface NSBezierPath (Additions) + (instancetype)bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius; @end -@implementation NSBezierPath (Compatibility) +@implementation NSBezierPath (Additions) + (instancetype)bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius { NSBezierPath *path = [NSBezierPath bezierPath]; diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index e6e74cf8..c425cb04 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -37,6 +37,8 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import +#import +#import #if SD_MAC || SD_UIKIT #import From 44d266af7c26d191be337f183439d129b08047df Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 18 Feb 2018 01:22:07 +0800 Subject: [PATCH 050/361] Add transformer property in manager level to allow a central control of image transform(optional) --- SDWebImage/SDWebImageDefine.h | 2 +- SDWebImage/SDWebImageManager.h | 8 ++++++++ SDWebImage/SDWebImageManager.m | 17 +++++++++++++---- SDWebImage/SDWebImageTransformer.h | 5 ++--- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index b3f5e726..4437d578 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -22,6 +22,6 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextSetIma FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustomManager; /** - A id instance which conforms SDWebImageTransformer protocol. It's used for image transform after the image load finished and store the transformed image to cache. (id) + A id instance which conforms SDWebImageTransformer protocol. It's used for image transform after the image load finished and store the transformed image to cache. If you provide one, it will ignore the `transformer` in manager and use provided one instead. (id) */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustomTransformer; diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index baf66ddb..d28ad8f7 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -10,6 +10,7 @@ #import "SDWebImageOperation.h" #import "SDWebImageDownloader.h" #import "SDImageCache.h" +#import "SDWebImageTransformer.h" typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { /** @@ -183,6 +184,13 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; @property (strong, nonatomic, readonly, nullable) SDImageCache *imageCache; @property (strong, nonatomic, readonly, nullable) SDWebImageDownloader *imageDownloader; +/** + The image transformer for manager. It's used for image transform after the image load finished and store the transformed image to cache, see `SDWebImageTransformer`. + Defaults to nil, which means no transform is applied. + @note This will affect all the load requests for this manager if you provide. However, you can pass `SDWebImageContextCustomTransformer` in context arg to explicitly use that transformer instead. + */ +@property (strong, nonatomic, nullable) id transformer; + /** * The cache filter is a block used each time SDWebImageManager need to convert an URL into a cache key. This can * be used to remove dynamic part of an image URL. diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 5e9ae917..c30a612d 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -8,8 +8,6 @@ #import "SDWebImageManager.h" #import "NSImage+Additions.h" -#import -#import "SDWebImageTransformer.h" @interface SDWebImageCombinedOperation : NSObject @@ -156,6 +154,18 @@ if (options & SDWebImageQueryDiskSync) cacheOptions |= SDImageCacheQueryDiskSync; if (options & SDWebImageTransformAnimatedImage) cacheOptions |= SDImageCacheTransformAnimatedImage; + // Image transformer + id transformer; + if ([context valueForKey:SDWebImageContextCustomTransformer]) { + transformer = [context valueForKey:SDWebImageContextCustomTransformer]; + } else if (self.transformer) { + // Transformer from manager + transformer = self.transformer; + NSMutableDictionary *mutableContext = [NSMutableDictionary dictionaryWithDictionary:context]; + [mutableContext setValue:transformer forKey:SDWebImageContextCustomTransformer]; + context = [mutableContext copy]; + } + __weak SDWebImageCombinedOperation *weakOperation = operation; operation.cacheOperation = [self.imageCache queryCacheOperationForKey:key options:cacheOptions done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) { __strong __typeof(weakOperation) strongOperation = weakOperation; @@ -240,9 +250,8 @@ if (options & SDWebImageRefreshCached && cachedImage && !downloadedImage) { // Image refresh hit the NSURLCache cache, do not call the completion block - } else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [context valueForKey:SDWebImageContextCustomTransformer]) { + } else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && transformer) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - id transformer = [context valueForKey:SDWebImageContextCustomTransformer]; UIImage *transformedImage = [transformer transformedImageWithImage:downloadedImage forKey:key]; if (transformedImage && finished) { NSString *transformerKey = [transformer transformerKey]; diff --git a/SDWebImage/SDWebImageTransformer.h b/SDWebImage/SDWebImageTransformer.h index 8080e47f..a060e6a3 100644 --- a/SDWebImage/SDWebImageTransformer.h +++ b/SDWebImage/SDWebImageTransformer.h @@ -11,8 +11,7 @@ /** A transformer protocol to transform the image load from cache or from download. - For cache, it store the transformed image to memory cache if the memory cache missed (Default). - For download, it store the transformed image to disk cache and memory cache if the download finished (Default). + You can provide transformer to cache and manager (Through the `transformer` property or context option `SDWebImageContextCustomTransformer`). @note The transform process is called from a global queue in order to not to block the main queue. */ @@ -42,7 +41,7 @@ // Separator for different transformerKey, for example, `image.png` |> flip(YES,NO) |> rotate(pi/4,YES) => 'image-SDWebImageFlippingTransformer(1,0)-SDWebImageRotationTransformer(0.78539816339,1).png' FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageTransformerKeySeparator; -// Pipeline transformer. Which you can bind multiple transformers together to let the image to be transformed one by one and generate the final image. +// Pipeline transformer. Which you can bind multiple transformers together to let the image to be transformed one by one in order and generate the final image. @interface SDWebImagePipelineTransformer : NSObject @property (nonatomic, copy, readonly, nonnull) NSArray> *transformers; From 8742e21fab0666afa8a084d12bce095be252bda3 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 19 Feb 2018 20:10:14 +0800 Subject: [PATCH 051/361] Do not expose the separator because of extensibility, use a function instead --- SDWebImage/SDImageCache.m | 2 +- SDWebImage/SDWebImageManager.m | 2 +- SDWebImage/SDWebImageTransformer.h | 12 +++++++++--- SDWebImage/SDWebImageTransformer.m | 12 ++++++++++-- SDWebImage/UIImage+Transform.m | 8 ++++---- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index a16b4600..d790aef8 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -538,7 +538,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { // grab the transformed disk image if transformer provided id transformer = [context valueForKey:SDWebImageContextCustomTransformer]; NSString *transformerKey = [transformer transformerKey]; - cacheKey = [[key stringByAppendingString:SDWebImageTransformerKeySeparator] stringByAppendingString:transformerKey]; + cacheKey = SDTransformedKeyForKey(key, transformerKey); } // decode image data only if in-memory cache missed diskImage = [self diskImageForKey:cacheKey data:diskData]; diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index c30a612d..f92ed841 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -255,7 +255,7 @@ UIImage *transformedImage = [transformer transformedImageWithImage:downloadedImage forKey:key]; if (transformedImage && finished) { NSString *transformerKey = [transformer transformerKey]; - NSString *cacheKey = [[key stringByAppendingString:SDWebImageTransformerKeySeparator] stringByAppendingString:transformerKey]; + NSString *cacheKey = SDTransformedKeyForKey(key, transformerKey); BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage]; NSData *cacheData; // pass nil if the image was transformed, so we can recalculate the data from the image diff --git a/SDWebImage/SDWebImageTransformer.h b/SDWebImage/SDWebImageTransformer.h index a060e6a3..624bbe4d 100644 --- a/SDWebImage/SDWebImageTransformer.h +++ b/SDWebImage/SDWebImageTransformer.h @@ -9,6 +9,15 @@ #import "SDWebImageCompat.h" #import "UIImage+Transform.h" +/** + Return the transformed cache key which applied with specify transformerKey. + + @param key The original cache key + @param transformerKey The transformer key from the transformer + @return The transformed cache key + */ +FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * _Nonnull transformerKey); + /** A transformer protocol to transform the image load from cache or from download. You can provide transformer to cache and manager (Through the `transformer` property or context option `SDWebImageContextCustomTransformer`). @@ -38,9 +47,6 @@ #pragma mark - Pipeline -// Separator for different transformerKey, for example, `image.png` |> flip(YES,NO) |> rotate(pi/4,YES) => 'image-SDWebImageFlippingTransformer(1,0)-SDWebImageRotationTransformer(0.78539816339,1).png' -FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageTransformerKeySeparator; - // Pipeline transformer. Which you can bind multiple transformers together to let the image to be transformed one by one in order and generate the final image. @interface SDWebImagePipelineTransformer : NSObject diff --git a/SDWebImage/SDWebImageTransformer.m b/SDWebImage/SDWebImageTransformer.m index 13da7fed..b7d63015 100644 --- a/SDWebImage/SDWebImageTransformer.m +++ b/SDWebImage/SDWebImageTransformer.m @@ -11,6 +11,16 @@ #import #endif +// Separator for different transformerKey, for example, `image.png` |> flip(YES,NO) |> rotate(pi/4,YES) => 'image-SDWebImageFlippingTransformer(1,0)-SDWebImageRotationTransformer(0.78539816339,1).png' +static NSString * const SDWebImageTransformerKeySeparator = @"-"; + +NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * _Nonnull transformerKey) { + if (!key || !transformerKey) { + return nil; + } + return [[key stringByAppendingString:SDWebImageTransformerKeySeparator] stringByAppendingString:transformerKey]; +} + @interface UIColor (Additions) @property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString; @@ -50,8 +60,6 @@ @end -NSString * const SDWebImageTransformerKeySeparator = @"-"; - @interface SDWebImagePipelineTransformer () @property (nonatomic, copy, readwrite, nonnull) NSArray> *transformers; diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index ecacfd09..543ed2b0 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -151,13 +151,13 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod #if SD_MAC @interface NSBezierPath (Additions) -+ (instancetype)bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius; ++ (instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius; @end @implementation NSBezierPath (Additions) -+ (instancetype)bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius { ++ (instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius { NSBezierPath *path = [NSBezierPath bezierPath]; CGFloat maxCorner = MIN(NSWidth(rect), NSHeight(rect)) / 2; @@ -246,7 +246,7 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod #if SD_UIKIT || SD_WATCH UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth) byRoundingCorners:corners cornerRadii:CGSizeMake(cornerRadius, cornerRadius)]; #else - NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth) byRoundingCorners:corners cornerRadius:cornerRadius]; + NSBezierPath *path = [NSBezierPath sd_bezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth) byRoundingCorners:corners cornerRadius:cornerRadius]; #endif [path closePath]; @@ -263,7 +263,7 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod #if SD_UIKIT || SD_WATCH UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:strokeRect byRoundingCorners:corners cornerRadii:CGSizeMake(strokeRadius, strokeRadius)]; #else - NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:strokeRect byRoundingCorners:corners cornerRadius:strokeRadius]; + NSBezierPath *path = [NSBezierPath sd_bezierPathWithRoundedRect:strokeRect byRoundingCorners:corners cornerRadius:strokeRadius]; #endif [path closePath]; From 01402c03692c0161ee0fdd92594b996c91b3ace3 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 19 Feb 2018 23:56:08 +0800 Subject: [PATCH 052/361] Add one `colorAtPoint` to help user get the pixel color. Expose the category for `UIColor` and `NSBezierPath` because it can be used in common cases --- SDWebImage/SDWebImageTransformer.m | 39 ------- SDWebImage/UIImage+Transform.h | 30 +++++ SDWebImage/UIImage+Transform.m | 175 ++++++++++++++++++++++++++++- 3 files changed, 199 insertions(+), 45 deletions(-) diff --git a/SDWebImage/SDWebImageTransformer.m b/SDWebImage/SDWebImageTransformer.m index b7d63015..86db61a2 100644 --- a/SDWebImage/SDWebImageTransformer.m +++ b/SDWebImage/SDWebImageTransformer.m @@ -21,45 +21,6 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * return [[key stringByAppendingString:SDWebImageTransformerKeySeparator] stringByAppendingString:transformerKey]; } -@interface UIColor (Additions) - -@property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString; - -@end - -@implementation UIColor (Additions) - -- (NSString *)sd_hexString { - CGFloat red, green, blue, alpha; -#if SD_UIKIT - if (![self getRed:&red green:&green blue:&blue alpha:&alpha]) { - [self getWhite:&red alpha:&alpha]; - green = red; - blue = red; - } -#else - @try { - [self getRed:&red green:&green blue:&blue alpha:&alpha]; - } - @catch (NSException *exception) { - [self getWhite:&red alpha:&alpha]; - green = red; - blue = red; - } -#endif - - red = roundf(red * 255.f); - green = roundf(green * 255.f); - blue = roundf(blue * 255.f); - alpha = roundf(alpha * 255.f); - - uint hex = ((uint)alpha << 24) | ((uint)red << 16) | ((uint)green << 8) | ((uint)blue); - - return [NSString stringWithFormat:@"0x%08x", hex]; -} - -@end - @interface SDWebImagePipelineTransformer () @property (nonatomic, copy, readwrite, nonnull) NSArray> *transformers; diff --git a/SDWebImage/UIImage+Transform.h b/SDWebImage/UIImage+Transform.h index c042977d..6165c53d 100644 --- a/SDWebImage/UIImage+Transform.h +++ b/SDWebImage/UIImage+Transform.h @@ -26,6 +26,28 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { }; #endif +#pragma mark - Useful category + +@interface UIColor (Additions) + +/** + Convenience way to get hex string from color. The output should always be 32-bit hex string like `0x00000000` + */ +@property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString; + +@end + +#if SD_MAC +@interface NSBezierPath (Additions) + +/** + Convenience way to create a bezier path with the specify rouunding corners on macOS. Same as the one on `UIBezierPath`. + */ ++ (instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius; + +@end +#endif + /** Provide some commen method for `UIImage`. Image process is based on Core Graphics and vImage. @@ -101,6 +123,14 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { */ - (nullable UIImage *)sd_tintedImageWithColor:(nonnull UIColor *)tintColor; +/** + Return the color at specify pixel. The postion is from the top-left to the bottom-right. And the color is always be RGBA format. + + @param point The position of pixel + @return The color for specify pixel, or nil if any error occur + */ +- (nullable UIColor *)sd_colorAtPoint:(CGPoint)point; + #pragma mark - Image Effect /** diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 543ed2b0..430fe79b 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -35,9 +35,6 @@ static CGContextRef SDCGContextCreateARGBBitmapContext(CGSize size, BOOL opaque, static void SDGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale) { #if SD_UIKIT || SD_WATCH UIGraphicsBeginImageContextWithOptions(size, opaque, scale); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextTranslateCTM(context, 0, -size.height); - CGContextScaleCTM(context, scale, -scale); #else CGContextRef context = SDCGContextCreateARGBBitmapContext(size, opaque, scale); if (!context) { @@ -148,13 +145,41 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod return rect; } -#if SD_MAC -@interface NSBezierPath (Additions) +@implementation UIColor (Additions) -+ (instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius; +- (NSString *)sd_hexString { + CGFloat red, green, blue, alpha; +#if SD_UIKIT + if (![self getRed:&red green:&green blue:&blue alpha:&alpha]) { + [self getWhite:&red alpha:&alpha]; + green = red; + blue = red; + } +#else + @try { + [self getRed:&red green:&green blue:&blue alpha:&alpha]; + } + @catch (NSException *exception) { + [self getWhite:&red alpha:&alpha]; + green = red; + blue = red; + } +#endif + + red = roundf(red * 255.f); + green = roundf(green * 255.f); + blue = roundf(blue * 255.f); + alpha = roundf(alpha * 255.f); + + uint hex = ((uint)alpha << 24) | ((uint)red << 16) | ((uint)green << 8) | ((uint)blue); + + return [NSString stringWithFormat:@"0x%08x", hex]; +} @end +#if SD_MAC + @implementation NSBezierPath (Additions) + (instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius { @@ -383,8 +408,146 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod return image; } +- (UIColor *)sd_colorAtPoint:(CGPoint)point { + if (!self) { + return nil; + } + CGImageRef imageRef = self.CGImage; + if (!imageRef) { + return nil; + } + + // Check point + CGFloat width = CGImageGetWidth(imageRef); + CGFloat height = CGImageGetHeight(imageRef); + if (point.x < 0 || point.y < 0 || point.x > width || point.y > height) { + return nil; + } + + // Get pixels + CGDataProviderRef provider = CGImageGetDataProvider(imageRef); + if (!provider) { + return nil; + } + CFDataRef data = CGDataProviderCopyData(provider); + if (!data) { + return nil; + } + + // Get pixel at point + size_t bytesPerRow = CGImageGetBytesPerRow(imageRef); // Actually should be ARGB8888, equal to width * 4(alpha) or 3(non-alpha) + size_t components = CGImageGetBitsPerPixel(imageRef) / CGImageGetBitsPerComponent(imageRef); + + CFRange range = CFRangeMake(bytesPerRow * point.y + components * point.x, 4); + if (CFDataGetLength(data) < range.location + range.length) { + return nil; + } + UInt8 pixel[4] = {0}; + CFDataGetBytes(data, range, pixel); + + // Convert to color + CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef); + CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); + CGFloat r = 0, g = 0, b = 0, a = 0; + + BOOL byteOrderNormal = NO; + switch (bitmapInfo & kCGBitmapByteOrderMask) { + case kCGBitmapByteOrderDefault: { + byteOrderNormal = YES; + } break; + case kCGBitmapByteOrder32Little: { + } break; + case kCGBitmapByteOrder32Big: { + byteOrderNormal = YES; + } break; + default: break; + } + switch (alphaInfo) { + case kCGImageAlphaPremultipliedFirst: { + if (byteOrderNormal) { + // ARGB8888 + a = pixel[0] / 255.0; + r = pixel[1] / 255.0; + g = pixel[2] / 255.0; + b = pixel[3] / 255.0; + } else { + // BGRA8888 + b = pixel[0] / 255.0; + g = pixel[1] / 255.0; + r = pixel[2] / 255.0; + a = pixel[3] / 255.0; + } + } + break; + case kCGImageAlphaPremultipliedLast: { + if (byteOrderNormal) { + // RGBA8888 + r = pixel[0] / 255.0; + g = pixel[1] / 255.0; + b = pixel[2] / 255.0; + a = pixel[3] / 255.0; + } else { + // ABGR8888 + a = pixel[0] / 255.0; + b = pixel[1] / 255.0; + g = pixel[2] / 255.0; + r = pixel[3] / 255.0; + } + } + break; + case kCGImageAlphaNone: { + if (byteOrderNormal) { + // RGB + r = pixel[0] / 255.0; + g = pixel[1] / 255.0; + b = pixel[2] / 255.0; + } else { + // BGR + b = pixel[0] / 255.0; + g = pixel[1] / 255.0; + r = pixel[2] / 255.0; + } + } + break; + case kCGImageAlphaNoneSkipLast: { + if (byteOrderNormal) { + // RGBX + r = pixel[0] / 255.0; + g = pixel[1] / 255.0; + b = pixel[2] / 255.0; + } else { + // XBGR + b = pixel[1] / 255.0; + g = pixel[2] / 255.0; + r = pixel[3] / 255.0; + } + } + break; + case kCGImageAlphaNoneSkipFirst: { + if (byteOrderNormal) { + // XRGB + r = pixel[1] / 255.0; + g = pixel[2] / 255.0; + b = pixel[3] / 255.0; + } else { + // BGRX + b = pixel[0] / 255.0; + g = pixel[1] / 255.0; + r = pixel[2] / 255.0; + } + } + break; + // iOS does not supports non-premultiplied alpha, so no these cases :) + default: + break; + } + + return [UIColor colorWithRed:r green:g blue:b alpha:a]; +} + #pragma mark - Image Effect +// We use vImage to do box convolve for performance. However, you can just use `CIFilter.CIBoxBlur`. For other blur effect, use any filter in `CICategoryBlur` - (UIImage *)sd_blurredImageWithRadius:(CGFloat)blurRadius { if (self.size.width < 1 || self.size.height < 1) { return nil; From d0df01bec1e00d6325805f94906a9868eb4675dc Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 19 Feb 2018 23:57:23 +0800 Subject: [PATCH 053/361] Complete the 8 tests for all image transform methods, well done --- Tests/Tests/SDCategoriesTests.m | 98 +++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m index b49378ed..5b814de4 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDCategoriesTests.m @@ -15,9 +15,12 @@ #import #import #import +#import @interface SDCategoriesTests : SDTestCase +@property (nonatomic, strong) UIImage *testImage; + @end @implementation SDCategoriesTests @@ -65,8 +68,98 @@ expect(image).notTo.beNil(); } +// UIImage+Transform test is hard to write because it's more about visual effect. Current it's tied to the `TestImage.png`, please keep that image or write new test with new image +- (void)test05UIImageTransformResize { + CGSize size = CGSizeMake(200, 100); + UIImage *resizedImage = [self.testImage sd_resizedImageWithSize:size scaleMode:SDImageScaleModeFill]; + expect(CGSizeEqualToSize(resizedImage.size, size)).beTruthy(); +} + +- (void)test06UIImageTransformCrop { + CGRect rect = CGRectMake(50, 50, 200, 200); + UIImage *croppedImage = [self.testImage sd_croppedImageWithRect:rect]; + expect(CGSizeEqualToSize(croppedImage.size, CGSizeMake(200, 200))).beTruthy(); + UIColor *startColor = [croppedImage sd_colorAtPoint:CGPointZero]; + expect([startColor.sd_hexString isEqualToString:@"0x00000000"]).beTruthy(); +} + +- (void)test07UIImageTransformRoundedCorner { + CGFloat radius = 50; + UIRectCorner corners = UIRectCornerAllCorners; + CGFloat borderWidth = 1; + UIColor *borderCoder = [UIColor blackColor]; + UIImage *roundedCornerImage = [self.testImage sd_roundedCornerImageWithRadius:radius corners:corners borderWidth:borderWidth borderColor:borderCoder]; + expect(CGSizeEqualToSize(roundedCornerImage.size, CGSizeMake(300, 300))).beTruthy(); + UIColor *startColor = [roundedCornerImage sd_colorAtPoint:CGPointZero]; + expect([startColor.sd_hexString isEqualToString:@"0x00000000"]).beTruthy(); + // Check the left center pixel, should be border :) + UIColor *checkBorderColor = [roundedCornerImage sd_colorAtPoint:CGPointMake(1, 150)]; + expect([checkBorderColor.sd_hexString isEqualToString:borderCoder.sd_hexString]).beTruthy(); +} + +- (void)test08UIImageTransformRotate { + CGFloat angle = M_PI_4; + UIImage *rotatedImage = [self.testImage sd_rotatedImageWithAngle:angle fitSize:NO]; + // Not fit size and no change + expect(CGSizeEqualToSize(rotatedImage.size, self.testImage.size)).beTruthy(); + // Fit size, may change size + rotatedImage = [self.testImage sd_rotatedImageWithAngle:angle fitSize:YES]; + CGSize rotatedSize = CGSizeMake(floor(300 * 1.414), floor(300 * 1.414)); // 45º, square length * sqrt(2) + expect(CGSizeEqualToSize(rotatedImage.size, rotatedSize)).beTruthy(); + rotatedImage = [self.testImage sd_rotatedImageWithAngle:angle fitSize:NO]; +} + +- (void)test09UIImageTransformFlip { + BOOL horizontal = YES; + BOOL vertical = YES; + UIImage *flippedImage = [self.testImage sd_flippedImageWithHorizontal:horizontal vertical:vertical]; + expect(CGSizeEqualToSize(flippedImage.size, self.testImage.size)).beTruthy(); +} + +- (void)test10UIImageTransformTint { + UIColor *tintColor = [UIColor blackColor]; + UIImage *tintedImage = [self.testImage sd_tintedImageWithColor:tintColor]; + expect(CGSizeEqualToSize(tintedImage.size, self.testImage.size)).beTruthy(); + // Check center color, should keep clear + UIColor *centerColor = [tintedImage sd_colorAtPoint:CGPointMake(150, 150)]; + expect([centerColor.sd_hexString isEqualToString:@"0x00000000"]); + // Check left color, should be tinted + UIColor *leftColor = [tintedImage sd_colorAtPoint:CGPointMake(80, 150)]; + expect([leftColor.sd_hexString isEqualToString:tintColor.sd_hexString]); +} + +- (void)test11UIImageTransformBlur { + CGFloat radius = 50; + UIImage *blurredImage = [self.testImage sd_blurredImageWithRadius:radius]; + expect(CGSizeEqualToSize(blurredImage.size, self.testImage.size)).beTruthy(); + // Check left color, should be blurred + UIColor *leftColor = [blurredImage sd_colorAtPoint:CGPointMake(80, 150)]; + // Hard-code from the output + UIColor *expectedColor = [UIColor colorWithRed:0.431373 green:0.101961 blue:0.0901961 alpha:0.729412]; + expect([leftColor.sd_hexString isEqualToString:expectedColor.sd_hexString]); +} + +- (void)test12UIImageTransformFilter { + // Invert color filter + CIFilter *filter = [CIFilter filterWithName:@"CIColorInvert"]; + UIImage *filteredImage = [self.testImage sd_filteredImageWithFilter:filter]; + expect(CGSizeEqualToSize(filteredImage.size, self.testImage.size)).beTruthy(); + // Check left color, should be inverted + UIColor *leftColor = [filteredImage sd_colorAtPoint:CGPointMake(80, 150)]; + // Hard-code from the output + UIColor *expectedColor = [UIColor colorWithRed:0.85098 green:0.992157 blue:0.992157 alpha:1]; + expect([leftColor.sd_hexString isEqualToString:expectedColor.sd_hexString]); +} + #pragma mark - Helper +- (UIImage *)testImage { + if (!_testImage) { + _testImage = [UIImage imageWithContentsOfFile:[self testPNGPath]]; + } + return _testImage; +} + - (NSString *)testJPEGPath { NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; return [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; @@ -82,4 +175,9 @@ return [testBundle pathForResource:@"TestImageStatic" ofType:@"webp"]; } +- (NSString *)testPNGPath { + NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; + return [testBundle pathForResource:@"TestImage" ofType:@"png"]; +} + @end From aea81791ec6dee08f6c21c561aab7f15682a1259 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 20 Feb 2018 00:04:31 +0800 Subject: [PATCH 054/361] Fix the test on macOS. Fix the issue when using rounded corner --- SDWebImage/UIImage+Transform.h | 2 +- SDWebImage/UIImage+Transform.m | 32 +++++--------------------------- Tests/Tests/SDCategoriesTests.m | 9 +++++++-- 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/SDWebImage/UIImage+Transform.h b/SDWebImage/UIImage+Transform.h index 6165c53d..44d1e807 100644 --- a/SDWebImage/UIImage+Transform.h +++ b/SDWebImage/UIImage+Transform.h @@ -43,7 +43,7 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { /** Convenience way to create a bezier path with the specify rouunding corners on macOS. Same as the one on `UIBezierPath`. */ -+ (instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius; ++ (nonnull instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius; @end #endif diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 430fe79b..076a23c9 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -81,29 +81,6 @@ static UIImage * SDGraphicsGetImageFromCurrentImageContext(void) { #endif } -static SDRectCorner SDRectCornerConvertCounterClockwise(SDRectCorner corners) { -#if SD_UIKIT || SD_WATCH - if (corners != UIRectCornerAllCorners) { - UIRectCorner tmp = 0; - if (corners & UIRectCornerTopLeft) tmp |= UIRectCornerBottomLeft; - if (corners & UIRectCornerTopRight) tmp |= UIRectCornerBottomRight; - if (corners & UIRectCornerBottomLeft) tmp |= UIRectCornerTopLeft; - if (corners & UIRectCornerBottomRight) tmp |= UIRectCornerTopRight; - corners = tmp; - } -#else - if (corners != SDRectCornerAllCorners) { - SDRectCorner tmp = 0; - if (corners & SDRectCornerTopLeft) tmp |= SDRectCornerBottomLeft; - if (corners & SDRectCornerTopRight) tmp |= SDRectCornerBottomRight; - if (corners & SDRectCornerBottomLeft) tmp |= SDRectCornerTopLeft; - if (corners & SDRectCornerBottomRight) tmp |= SDRectCornerTopRight; - corners = tmp; - } -#endif - return corners; -} - static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMode scaleMode) { rect = CGRectStandardize(rect); size.width = size.width < 0 ? -size.width : size.width; @@ -261,7 +238,6 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod - (UIImage *)sd_roundedCornerImageWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor { if (!self.CGImage) return nil; - corners = SDRectCornerConvertCounterClockwise(corners); SDGraphicsBeginImageContextWithOptions(self.size, NO, self.scale); CGContextRef context = SDGraphicsGetCurrentContext(); CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height); @@ -463,7 +439,8 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod default: break; } switch (alphaInfo) { - case kCGImageAlphaPremultipliedFirst: { + case kCGImageAlphaPremultipliedFirst: + case kCGImageAlphaFirst: { if (byteOrderNormal) { // ARGB8888 a = pixel[0] / 255.0; @@ -479,7 +456,8 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod } } break; - case kCGImageAlphaPremultipliedLast: { + case kCGImageAlphaPremultipliedLast: + case kCGImageAlphaLast: { if (byteOrderNormal) { // RGBA8888 r = pixel[0] / 255.0; @@ -537,7 +515,7 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod } } break; - // iOS does not supports non-premultiplied alpha, so no these cases :) + case kCGImageAlphaOnly: default: break; } diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m index 5b814de4..486f9a36 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDCategoriesTests.m @@ -16,6 +16,7 @@ #import #import #import +#import @interface SDCategoriesTests : SDTestCase @@ -85,7 +86,11 @@ - (void)test07UIImageTransformRoundedCorner { CGFloat radius = 50; - UIRectCorner corners = UIRectCornerAllCorners; +#if SD_UIKIT + SDRectCorner corners = UIRectCornerAllCorners; +#else + SDRectCorner corners = SDRectCornerAllCorners; +#endif CGFloat borderWidth = 1; UIColor *borderCoder = [UIColor blackColor]; UIImage *roundedCornerImage = [self.testImage sd_roundedCornerImageWithRadius:radius corners:corners borderWidth:borderWidth borderColor:borderCoder]; @@ -155,7 +160,7 @@ - (UIImage *)testImage { if (!_testImage) { - _testImage = [UIImage imageWithContentsOfFile:[self testPNGPath]]; + _testImage = [[UIImage alloc] initWithContentsOfFile:[self testPNGPath]]; } return _testImage; } From 3e3ec8d513eaeae51336c18ed679c02ffe919c62 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 20 Feb 2018 01:37:30 +0800 Subject: [PATCH 055/361] Change the hex color from 0x00000000 format to #00000000 --- SDWebImage/UIImage+Transform.h | 2 +- SDWebImage/UIImage+Transform.m | 2 +- Tests/Tests/SDCategoriesTests.m | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/SDWebImage/UIImage+Transform.h b/SDWebImage/UIImage+Transform.h index 44d1e807..87a8a969 100644 --- a/SDWebImage/UIImage+Transform.h +++ b/SDWebImage/UIImage+Transform.h @@ -31,7 +31,7 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { @interface UIColor (Additions) /** - Convenience way to get hex string from color. The output should always be 32-bit hex string like `0x00000000` + Convenience way to get hex string from color. The output should always be 32-bit hex string like `#00000000`. */ @property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString; diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 076a23c9..5bcb6c83 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -150,7 +150,7 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod uint hex = ((uint)alpha << 24) | ((uint)red << 16) | ((uint)green << 8) | ((uint)blue); - return [NSString stringWithFormat:@"0x%08x", hex]; + return [NSString stringWithFormat:@"#%08x", hex]; } @end diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m index 486f9a36..a788173a 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDCategoriesTests.m @@ -81,7 +81,7 @@ UIImage *croppedImage = [self.testImage sd_croppedImageWithRect:rect]; expect(CGSizeEqualToSize(croppedImage.size, CGSizeMake(200, 200))).beTruthy(); UIColor *startColor = [croppedImage sd_colorAtPoint:CGPointZero]; - expect([startColor.sd_hexString isEqualToString:@"0x00000000"]).beTruthy(); + expect([startColor.sd_hexString isEqualToString:[UIColor clearColor].sd_hexString]).beTruthy(); } - (void)test07UIImageTransformRoundedCorner { @@ -96,7 +96,7 @@ UIImage *roundedCornerImage = [self.testImage sd_roundedCornerImageWithRadius:radius corners:corners borderWidth:borderWidth borderColor:borderCoder]; expect(CGSizeEqualToSize(roundedCornerImage.size, CGSizeMake(300, 300))).beTruthy(); UIColor *startColor = [roundedCornerImage sd_colorAtPoint:CGPointZero]; - expect([startColor.sd_hexString isEqualToString:@"0x00000000"]).beTruthy(); + expect([startColor.sd_hexString isEqualToString:[UIColor clearColor].sd_hexString]).beTruthy(); // Check the left center pixel, should be border :) UIColor *checkBorderColor = [roundedCornerImage sd_colorAtPoint:CGPointMake(1, 150)]; expect([checkBorderColor.sd_hexString isEqualToString:borderCoder.sd_hexString]).beTruthy(); @@ -127,7 +127,7 @@ expect(CGSizeEqualToSize(tintedImage.size, self.testImage.size)).beTruthy(); // Check center color, should keep clear UIColor *centerColor = [tintedImage sd_colorAtPoint:CGPointMake(150, 150)]; - expect([centerColor.sd_hexString isEqualToString:@"0x00000000"]); + expect([centerColor.sd_hexString isEqualToString:[UIColor clearColor].sd_hexString]); // Check left color, should be tinted UIColor *leftColor = [tintedImage sd_colorAtPoint:CGPointMake(80, 150)]; expect([leftColor.sd_hexString isEqualToString:tintColor.sd_hexString]); From 57408d83132e358bcdcd9731b86099947aa2c383 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 21 Feb 2018 20:25:30 +0800 Subject: [PATCH 056/361] Fix the potential leak of CFDataRef --- SDWebImage/UIImage+Transform.h | 3 ++- SDWebImage/UIImage+Transform.m | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/SDWebImage/UIImage+Transform.h b/SDWebImage/UIImage+Transform.h index 87a8a969..cbdbc212 100644 --- a/SDWebImage/UIImage+Transform.h +++ b/SDWebImage/UIImage+Transform.h @@ -124,7 +124,8 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { - (nullable UIImage *)sd_tintedImageWithColor:(nonnull UIColor *)tintColor; /** - Return the color at specify pixel. The postion is from the top-left to the bottom-right. And the color is always be RGBA format. + Return the color at specify pixel. The point is from the top-left to the bottom-right and 0-based. The returned the color is always be RGBA format. + @note The point's x/y should not be smaller than 0, or greater than or equal to width/height. @param point The position of pixel @return The color for specify pixel, or nil if any error occur diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 5bcb6c83..7e66680a 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -396,7 +396,7 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod // Check point CGFloat width = CGImageGetWidth(imageRef); CGFloat height = CGImageGetHeight(imageRef); - if (point.x < 0 || point.y < 0 || point.x > width || point.y > height) { + if (point.x < 0 || point.y < 0 || point.x >= width || point.y >= height) { return nil; } @@ -411,15 +411,17 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod } // Get pixel at point - size_t bytesPerRow = CGImageGetBytesPerRow(imageRef); // Actually should be ARGB8888, equal to width * 4(alpha) or 3(non-alpha) + size_t bytesPerRow = CGImageGetBytesPerRow(imageRef); size_t components = CGImageGetBitsPerPixel(imageRef) / CGImageGetBitsPerComponent(imageRef); CFRange range = CFRangeMake(bytesPerRow * point.y + components * point.x, 4); if (CFDataGetLength(data) < range.location + range.length) { + CFRelease(data); return nil; } UInt8 pixel[4] = {0}; CFDataGetBytes(data, range, pixel); + CFRelease(data); // Convert to color CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef); From a2076d362e2a3bda694f86c29a59199ee044b85e Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 21 Feb 2018 20:41:05 +0800 Subject: [PATCH 057/361] Add sd_colorsWithRect method and test, treat RGB color with default alpha 1.0 --- SDWebImage/UIImage+Transform.h | 19 ++- SDWebImage/UIImage+Transform.m | 263 ++++++++++++++++++++------------ Tests/Tests/SDCategoriesTests.m | 8 + 3 files changed, 188 insertions(+), 102 deletions(-) diff --git a/SDWebImage/UIImage+Transform.h b/SDWebImage/UIImage+Transform.h index cbdbc212..f02a73d6 100644 --- a/SDWebImage/UIImage+Transform.h +++ b/SDWebImage/UIImage+Transform.h @@ -31,7 +31,7 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { @interface UIColor (Additions) /** - Convenience way to get hex string from color. The output should always be 32-bit hex string like `#00000000`. + Convenience way to get hex string from color. The output should always be 32-bit RGBA hex string like `#00000000`. */ @property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString; @@ -116,22 +116,33 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { #pragma mark - Image Blending /** - Return a tinted image in alpha channel with the given color. + Return a tinted image with the given color. This actually use alpha blending of current image and the tint color. - @param tintColor The color. + @param tintColor The tint color. @return The new image with the tint color. */ - (nullable UIImage *)sd_tintedImageWithColor:(nonnull UIColor *)tintColor; /** - Return the color at specify pixel. The point is from the top-left to the bottom-right and 0-based. The returned the color is always be RGBA format. + Return the pixel color at specify position. The point is from the top-left to the bottom-right and 0-based. The returned the color is always be RGBA format. The image must be CG-based. @note The point's x/y should not be smaller than 0, or greater than or equal to width/height. + @note The overhead of object creation means this method is best suited for infrequent color sampling. For heavy image processing, grab the raw bitmap data and process yourself. @param point The position of pixel @return The color for specify pixel, or nil if any error occur */ - (nullable UIColor *)sd_colorAtPoint:(CGPoint)point; +/** + Return the pixel color array with specify rectangle. The rect is from the top-left to the bottom-right and 0-based. The returned the color is always be RGBA format. The image must be CG-based. + @note The rect's width/height should not be smaller than or equal to 0. The minX/minY should not be smaller than 0. The maxX/maxY should not be greater than width/height. Attention this limit is different from point(point: (0,0) like rect: (0, 0, 1, 1)) + @note The overhead of object creation means this method is best suited for infrequent color sampling. For heavy image processing, grab the raw bitmap data and process yourself. + + @param rect The rectangle of pixels + @return The color array for specify pixels, or nil if any error occur + */ +- (nullable NSArray *)sd_colorsWithRect:(CGRect)rect; + #pragma mark - Image Effect /** diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 7e66680a..4d06a67a 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -81,7 +81,7 @@ static UIImage * SDGraphicsGetImageFromCurrentImageContext(void) { #endif } -static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMode scaleMode) { +static inline CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMode scaleMode) { rect = CGRectStandardize(rect); size.width = size.width < 0 ? -size.width : size.width; size.height = size.height < 0 ? -size.height : size.height; @@ -122,6 +122,109 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod return rect; } +static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitmapInfo) { + // Get alpha info, byteOrder info + CGImageAlphaInfo alphaInfo = bitmapInfo & kCGBitmapAlphaInfoMask; + CGImageByteOrderInfo byteOrderInfo = bitmapInfo & kCGBitmapByteOrderMask; + CGFloat r = 0, g = 0, b = 0, a = 255.0; + + BOOL byteOrderNormal = NO; + switch (byteOrderInfo) { + case kCGBitmapByteOrderDefault: { + byteOrderNormal = YES; + } break; + case kCGBitmapByteOrder32Little: { + } break; + case kCGBitmapByteOrder32Big: { + byteOrderNormal = YES; + } break; + default: break; + } + switch (alphaInfo) { + case kCGImageAlphaPremultipliedFirst: + case kCGImageAlphaFirst: { + if (byteOrderNormal) { + // ARGB8888 + a = pixel[0] / 255.0; + r = pixel[1] / 255.0; + g = pixel[2] / 255.0; + b = pixel[3] / 255.0; + } else { + // BGRA8888 + b = pixel[0] / 255.0; + g = pixel[1] / 255.0; + r = pixel[2] / 255.0; + a = pixel[3] / 255.0; + } + } + break; + case kCGImageAlphaPremultipliedLast: + case kCGImageAlphaLast: { + if (byteOrderNormal) { + // RGBA8888 + r = pixel[0] / 255.0; + g = pixel[1] / 255.0; + b = pixel[2] / 255.0; + a = pixel[3] / 255.0; + } else { + // ABGR8888 + a = pixel[0] / 255.0; + b = pixel[1] / 255.0; + g = pixel[2] / 255.0; + r = pixel[3] / 255.0; + } + } + break; + case kCGImageAlphaNone: { + if (byteOrderNormal) { + // RGB + r = pixel[0] / 255.0; + g = pixel[1] / 255.0; + b = pixel[2] / 255.0; + } else { + // BGR + b = pixel[0] / 255.0; + g = pixel[1] / 255.0; + r = pixel[2] / 255.0; + } + } + break; + case kCGImageAlphaNoneSkipLast: { + if (byteOrderNormal) { + // RGBX + r = pixel[0] / 255.0; + g = pixel[1] / 255.0; + b = pixel[2] / 255.0; + } else { + // XBGR + b = pixel[1] / 255.0; + g = pixel[2] / 255.0; + r = pixel[3] / 255.0; + } + } + break; + case kCGImageAlphaNoneSkipFirst: { + if (byteOrderNormal) { + // XRGB + r = pixel[1] / 255.0; + g = pixel[2] / 255.0; + b = pixel[3] / 255.0; + } else { + // BGRX + b = pixel[0] / 255.0; + g = pixel[1] / 255.0; + r = pixel[2] / 255.0; + } + } + break; + case kCGImageAlphaOnly: + default: + break; + } + + return [UIColor colorWithRed:r green:g blue:b alpha:a]; +} + @implementation UIColor (Additions) - (NSString *)sd_hexString { @@ -419,115 +522,79 @@ static CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMod CFRelease(data); return nil; } - UInt8 pixel[4] = {0}; + Pixel_8888 pixel = {0}; CFDataGetBytes(data, range, pixel); CFRelease(data); // Convert to color - CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef); CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); - CGFloat r = 0, g = 0, b = 0, a = 0; - - BOOL byteOrderNormal = NO; - switch (bitmapInfo & kCGBitmapByteOrderMask) { - case kCGBitmapByteOrderDefault: { - byteOrderNormal = YES; - } break; - case kCGBitmapByteOrder32Little: { - } break; - case kCGBitmapByteOrder32Big: { - byteOrderNormal = YES; - } break; - default: break; + return SDGetColorFromPixel(pixel, bitmapInfo); +} + +- (NSArray *)sd_colorsWithRect:(CGRect)rect { + if (!self) { + return nil; } - switch (alphaInfo) { - case kCGImageAlphaPremultipliedFirst: - case kCGImageAlphaFirst: { - if (byteOrderNormal) { - // ARGB8888 - a = pixel[0] / 255.0; - r = pixel[1] / 255.0; - g = pixel[2] / 255.0; - b = pixel[3] / 255.0; - } else { - // BGRA8888 - b = pixel[0] / 255.0; - g = pixel[1] / 255.0; - r = pixel[2] / 255.0; - a = pixel[3] / 255.0; - } - } - break; - case kCGImageAlphaPremultipliedLast: - case kCGImageAlphaLast: { - if (byteOrderNormal) { - // RGBA8888 - r = pixel[0] / 255.0; - g = pixel[1] / 255.0; - b = pixel[2] / 255.0; - a = pixel[3] / 255.0; - } else { - // ABGR8888 - a = pixel[0] / 255.0; - b = pixel[1] / 255.0; - g = pixel[2] / 255.0; - r = pixel[3] / 255.0; - } - } - break; - case kCGImageAlphaNone: { - if (byteOrderNormal) { - // RGB - r = pixel[0] / 255.0; - g = pixel[1] / 255.0; - b = pixel[2] / 255.0; - } else { - // BGR - b = pixel[0] / 255.0; - g = pixel[1] / 255.0; - r = pixel[2] / 255.0; - } - } - break; - case kCGImageAlphaNoneSkipLast: { - if (byteOrderNormal) { - // RGBX - r = pixel[0] / 255.0; - g = pixel[1] / 255.0; - b = pixel[2] / 255.0; - } else { - // XBGR - b = pixel[1] / 255.0; - g = pixel[2] / 255.0; - r = pixel[3] / 255.0; - } - } - break; - case kCGImageAlphaNoneSkipFirst: { - if (byteOrderNormal) { - // XRGB - r = pixel[1] / 255.0; - g = pixel[2] / 255.0; - b = pixel[3] / 255.0; - } else { - // BGRX - b = pixel[0] / 255.0; - g = pixel[1] / 255.0; - r = pixel[2] / 255.0; - } - } - break; - case kCGImageAlphaOnly: - default: - break; + CGImageRef imageRef = self.CGImage; + if (!imageRef) { + return nil; } - return [UIColor colorWithRed:r green:g blue:b alpha:a]; + // Check rect + CGFloat width = CGImageGetWidth(imageRef); + CGFloat height = CGImageGetHeight(imageRef); + if (CGRectGetWidth(rect) <= 0 || CGRectGetHeight(rect) <= 0 || CGRectGetMinX(rect) < 0 || CGRectGetMinY(rect) < 0 || CGRectGetMaxX(rect) > width || CGRectGetMaxY(rect) > height) { + return nil; + } + + // Get pixels + CGDataProviderRef provider = CGImageGetDataProvider(imageRef); + if (!provider) { + return nil; + } + CFDataRef data = CGDataProviderCopyData(provider); + if (!data) { + return nil; + } + + // Get pixels with rect + size_t bytesPerRow = CGImageGetBytesPerRow(imageRef); + size_t components = CGImageGetBitsPerPixel(imageRef) / CGImageGetBitsPerComponent(imageRef); + + size_t start = bytesPerRow * CGRectGetMinY(rect) + components * CGRectGetMinX(rect); + size_t end = bytesPerRow * (CGRectGetMaxY(rect) - 1) + components * CGRectGetMaxX(rect); + if (CFDataGetLength(data) < (CFIndex)end) { + CFRelease(data); + return nil; + } + + const UInt8 *pixels = CFDataGetBytePtr(data); + size_t row = CGRectGetMinY(rect); + size_t col = CGRectGetMaxX(rect); + + // Convert to color + CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); + NSMutableArray *colors = [NSMutableArray arrayWithCapacity:CGRectGetWidth(rect) * CGRectGetHeight(rect)]; + for (size_t index = start; index < end; index += 4) { + if (index >= row * bytesPerRow + col * components) { + // Index beyond the end of current row, go next row + row++; + index = row * bytesPerRow + CGRectGetMinX(rect) * components; + index -= 4; + continue; + } + Pixel_8888 pixel = {pixels[index], pixels[index+1], pixels[index+2], pixels[index+3]}; + UIColor *color = SDGetColorFromPixel(pixel, bitmapInfo); + [colors addObject:color]; + } + CFRelease(data); + + return [colors copy]; } #pragma mark - Image Effect -// We use vImage to do box convolve for performance. However, you can just use `CIFilter.CIBoxBlur`. For other blur effect, use any filter in `CICategoryBlur` +// We use vImage to do box convolve for performance and support for watchOS. However, you can just use `CIFilter.CIBoxBlur`. For other blur effect, use any filter in `CICategoryBlur` - (UIImage *)sd_blurredImageWithRadius:(CGFloat)blurRadius { if (self.size.width < 1 || self.size.height < 1) { return nil; diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m index a788173a..04247172 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDCategoriesTests.m @@ -119,6 +119,14 @@ BOOL vertical = YES; UIImage *flippedImage = [self.testImage sd_flippedImageWithHorizontal:horizontal vertical:vertical]; expect(CGSizeEqualToSize(flippedImage.size, self.testImage.size)).beTruthy(); + // Test pixel colors method here + UIColor *checkColor = [flippedImage sd_colorAtPoint:CGPointMake(75, 75)]; + expect(checkColor); + NSArray *checkColors = [flippedImage sd_colorsWithRect:CGRectMake(75, 75, 10, 10)]; // Rect are all same color + expect(checkColors.count).to.equal(10 * 10); + for (UIColor *color in checkColors) { + expect([color isEqual:checkColor]).to.beTruthy(); + } } - (void)test10UIImageTransformTint { From 67285ee722785229d115f0afd0becc2ced86f2d3 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 17 Mar 2018 20:56:20 +0800 Subject: [PATCH 058/361] Add the test for transformer property --- SDWebImage/UIImage+Transform.h | 2 +- .../project.pbxproj | 8 +++++++ Tests/Tests/SDWebImageManagerTests.m | 20 +++++++++++++++++ Tests/Tests/SDWebImageTestTransformer.h | 16 ++++++++++++++ Tests/Tests/SDWebImageTestTransformer.m | 22 +++++++++++++++++++ 5 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 Tests/Tests/SDWebImageTestTransformer.h create mode 100644 Tests/Tests/SDWebImageTestTransformer.m diff --git a/SDWebImage/UIImage+Transform.h b/SDWebImage/UIImage+Transform.h index f02a73d6..c5d64549 100644 --- a/SDWebImage/UIImage+Transform.h +++ b/SDWebImage/UIImage+Transform.h @@ -41,7 +41,7 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { @interface NSBezierPath (Additions) /** - Convenience way to create a bezier path with the specify rouunding corners on macOS. Same as the one on `UIBezierPath`. + Convenience way to create a bezier path with the specify rounding corners on macOS. Same as the one on `UIBezierPath`. */ + (nonnull instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius; diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index b181c4a8..790c3e7e 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -12,6 +12,8 @@ 2D7AF0601F329763000083C2 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; }; 321259EC1F39E3240096FE0E /* TestImageStatic.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259EB1F39E3240096FE0E /* TestImageStatic.webp */; }; 321259EE1F39E4110096FE0E /* TestImageAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */; }; + 3264FF2F205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */; }; + 3264FF30205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */; }; 32B99E8B203AF8690017FD66 /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */; }; 32B99E9B203B2EDD0017FD66 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; }; 32B99E9C203B2EE40017FD66 /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */; }; @@ -56,6 +58,8 @@ 2D7AF05F1F329763000083C2 /* SDTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDTestCase.m; sourceTree = ""; }; 321259EB1F39E3240096FE0E /* TestImageStatic.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageStatic.webp; sourceTree = ""; }; 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageAnimated.webp; sourceTree = ""; }; + 3264FF2D205D42CB00F6BD48 /* SDWebImageTestTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestTransformer.h; sourceTree = ""; }; + 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestTransformer.m; sourceTree = ""; }; 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDCategoriesTests.m; sourceTree = ""; }; 32B99E92203B2DF90017FD66 /* Tests Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 32B99E96203B2DF90017FD66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -193,6 +197,8 @@ 2D7AF05F1F329763000083C2 /* SDTestCase.m */, 32E6F0301F3A1B4700A945E6 /* SDWebImageTestDecoder.h */, 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */, + 3264FF2D205D42CB00F6BD48 /* SDWebImageTestTransformer.h */, + 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */, ); path = Tests; sourceTree = ""; @@ -447,6 +453,7 @@ 32B99E9E203B2F810017FD66 /* SDMockFileManager.m in Sources */, 32B99EAB203B36620017FD66 /* SDWebImageManagerTests.m in Sources */, 32B99EA9203B34B60017FD66 /* SDWebImageDecoderTests.m in Sources */, + 3264FF30205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */, 32B99E9B203B2EDD0017FD66 /* SDTestCase.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -464,6 +471,7 @@ DA248D69195475D800390AB0 /* SDImageCacheTests.m in Sources */, DA248D6B195476AC00390AB0 /* SDWebImageManagerTests.m in Sources */, 32B99E8B203AF8690017FD66 /* SDCategoriesTests.m in Sources */, + 3264FF2F205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */, 433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Tests/Tests/SDWebImageManagerTests.m b/Tests/Tests/SDWebImageManagerTests.m index 4c79f24f..8ee3a567 100644 --- a/Tests/Tests/SDWebImageManagerTests.m +++ b/Tests/Tests/SDWebImageManagerTests.m @@ -8,6 +8,7 @@ #import "SDTestCase.h" #import +#import "SDWebImageTestTransformer.h" @interface SDWebImageManagerTests : SDTestCase @@ -135,4 +136,23 @@ [self waitForExpectationsWithTimeout:kAsyncTestTimeout * 2 handler:nil]; } +- (void)test08ThatImageTransformerWork { + XCTestExpectation *expectation = [self expectationWithDescription:@"Image transformer work"]; + NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; + SDWebImageTestTransformer *transformer = [[SDWebImageTestTransformer alloc] init]; + NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; + NSString *testImagePath = [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; + transformer.testImage = [[UIImage alloc] initWithContentsOfFile:testImagePath]; + SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:[SDImageCache sharedImageCache] downloader:[SDWebImageDownloader sharedDownloader]]; + manager.transformer = transformer; + [[SDImageCache sharedImageCache] removeImageForKey:kTestJpegURL withCompletion:^{ + [manager loadImageWithURL:imageURL options:SDWebImageTransformAnimatedImage progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + expect(image).equal(transformer.testImage); + [expectation fulfill]; + }]; + }]; + + [self waitForExpectationsWithCommonTimeout]; +} + @end diff --git a/Tests/Tests/SDWebImageTestTransformer.h b/Tests/Tests/SDWebImageTestTransformer.h new file mode 100644 index 00000000..2f9040e8 --- /dev/null +++ b/Tests/Tests/SDWebImageTestTransformer.h @@ -0,0 +1,16 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Matt Galloway + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import + +@interface SDWebImageTestTransformer : NSObject + +@property (nonatomic, strong, nullable) UIImage *testImage; + +@end diff --git a/Tests/Tests/SDWebImageTestTransformer.m b/Tests/Tests/SDWebImageTestTransformer.m new file mode 100644 index 00000000..0afafe76 --- /dev/null +++ b/Tests/Tests/SDWebImageTestTransformer.m @@ -0,0 +1,22 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Matt Galloway + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageTestTransformer.h" + +@implementation SDWebImageTestTransformer + +- (NSString *)transformerKey { + return @"SDWebImageTestTransformer"; +} + +- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { + return self.testImage; +} + +@end From ed0100c323caed26e2817251700472f426eb64fc Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 18 Mar 2018 22:05:47 +0800 Subject: [PATCH 059/361] Move the NSBezierPath and UIColor category into implementation because it's now for internal use only --- SDWebImage/SDWebImageTransformer.m | 42 ++++++++++++++++++++++++++ SDWebImage/UIImage+Transform.h | 24 +-------------- SDWebImage/UIImage+Transform.m | 48 +++++++----------------------- Tests/Tests/SDCategoriesTests.m | 7 +++++ 4 files changed, 60 insertions(+), 61 deletions(-) diff --git a/SDWebImage/SDWebImageTransformer.m b/SDWebImage/SDWebImageTransformer.m index 86db61a2..80ca3394 100644 --- a/SDWebImage/SDWebImageTransformer.m +++ b/SDWebImage/SDWebImageTransformer.m @@ -21,6 +21,48 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * return [[key stringByAppendingString:SDWebImageTransformerKeySeparator] stringByAppendingString:transformerKey]; } +@interface UIColor (HexString) + +/** + Convenience way to get hex string from color. The output should always be 32-bit RGBA hex string like `#00000000`. + */ +@property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString; + +@end + +@implementation UIColor (HexString) + +- (NSString *)sd_hexString { + CGFloat red, green, blue, alpha; +#if SD_UIKIT + if (![self getRed:&red green:&green blue:&blue alpha:&alpha]) { + [self getWhite:&red alpha:&alpha]; + green = red; + blue = red; + } +#else + @try { + [self getRed:&red green:&green blue:&blue alpha:&alpha]; + } + @catch (NSException *exception) { + [self getWhite:&red alpha:&alpha]; + green = red; + blue = red; + } +#endif + + red = roundf(red * 255.f); + green = roundf(green * 255.f); + blue = roundf(blue * 255.f); + alpha = roundf(alpha * 255.f); + + uint hex = ((uint)alpha << 24) | ((uint)red << 16) | ((uint)green << 8) | ((uint)blue); + + return [NSString stringWithFormat:@"#%08x", hex]; +} + +@end + @interface SDWebImagePipelineTransformer () @property (nonatomic, copy, readwrite, nonnull) NSArray> *transformers; diff --git a/SDWebImage/UIImage+Transform.h b/SDWebImage/UIImage+Transform.h index c5d64549..ff999bba 100644 --- a/SDWebImage/UIImage+Transform.h +++ b/SDWebImage/UIImage+Transform.h @@ -26,28 +26,6 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { }; #endif -#pragma mark - Useful category - -@interface UIColor (Additions) - -/** - Convenience way to get hex string from color. The output should always be 32-bit RGBA hex string like `#00000000`. - */ -@property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString; - -@end - -#if SD_MAC -@interface NSBezierPath (Additions) - -/** - Convenience way to create a bezier path with the specify rounding corners on macOS. Same as the one on `UIBezierPath`. - */ -+ (nonnull instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius; - -@end -#endif - /** Provide some commen method for `UIImage`. Image process is based on Core Graphics and vImage. @@ -135,7 +113,7 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { /** Return the pixel color array with specify rectangle. The rect is from the top-left to the bottom-right and 0-based. The returned the color is always be RGBA format. The image must be CG-based. - @note The rect's width/height should not be smaller than or equal to 0. The minX/minY should not be smaller than 0. The maxX/maxY should not be greater than width/height. Attention this limit is different from point(point: (0,0) like rect: (0, 0, 1, 1)) + @note The rect's width/height should not be smaller than or equal to 0. The minX/minY should not be smaller than 0. The maxX/maxY should not be greater than width/height. Attention this limit is different from `sd_colorAtPoint:` (point: (0, 0) like rect: (0, 0, 1, 1)) @note The overhead of object creation means this method is best suited for infrequent color sampling. For heavy image processing, grab the raw bitmap data and process yourself. @param rect The rectangle of pixels diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 4d06a67a..f1c9f513 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -13,10 +13,6 @@ #import #endif -#ifndef SD_SWAP // swap two value -#define SD_SWAP(_a_, _b_) do { __typeof__(_a_) _tmp_ = (_a_); (_a_) = (_b_); (_b_) = _tmp_; } while (0) -#endif - #if SD_MAC static CGContextRef SDCGContextCreateARGBBitmapContext(CGSize size, BOOL opaque, CGFloat scale) { size_t width = ceil(size.width * scale); @@ -225,42 +221,17 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma return [UIColor colorWithRed:r green:g blue:b alpha:a]; } -@implementation UIColor (Additions) +#if SD_MAC +@interface NSBezierPath (RoundedCorners) -- (NSString *)sd_hexString { - CGFloat red, green, blue, alpha; -#if SD_UIKIT - if (![self getRed:&red green:&green blue:&blue alpha:&alpha]) { - [self getWhite:&red alpha:&alpha]; - green = red; - blue = red; - } -#else - @try { - [self getRed:&red green:&green blue:&blue alpha:&alpha]; - } - @catch (NSException *exception) { - [self getWhite:&red alpha:&alpha]; - green = red; - blue = red; - } -#endif - - red = roundf(red * 255.f); - green = roundf(green * 255.f); - blue = roundf(blue * 255.f); - alpha = roundf(alpha * 255.f); - - uint hex = ((uint)alpha << 24) | ((uint)red << 16) | ((uint)green << 8) | ((uint)blue); - - return [NSString stringWithFormat:@"#%08x", hex]; -} +/** + Convenience way to create a bezier path with the specify rounding corners on macOS. Same as the one on `UIBezierPath`. + */ ++ (nonnull instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius; @end -#if SD_MAC - -@implementation NSBezierPath (Additions) +@implementation NSBezierPath (RoundedCorners) + (instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius { NSBezierPath *path = [NSBezierPath bezierPath]; @@ -288,7 +259,6 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma } @end - #endif @implementation UIImage (Transform) @@ -664,7 +634,9 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma void *temp = malloc(tempSize); for (int i = 0; i < iterations; i++) { vImageBoxConvolve_ARGB8888(input, output, temp, 0, 0, radius, radius, NULL, kvImageEdgeExtend); - SD_SWAP(input, output); + vImage_Buffer *tmp = input; + input = output; + output = tmp; } free(temp); } diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m index 04247172..0d00aa09 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDCategoriesTests.m @@ -18,6 +18,13 @@ #import #import +// Internal header +@interface UIColor (HexString) + +@property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString; + +@end + @interface SDCategoriesTests : SDTestCase @property (nonatomic, strong) UIImage *testImage; From ec7927b25ab96ebe641d113b9aff84de602ac8ca Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 23 Mar 2018 01:45:53 +0800 Subject: [PATCH 060/361] Update the transformer to use as immutable class. Move the tests into SDWebImageTransformerTests --- SDWebImage/SDWebImageTransformer.h | 34 ++-- SDWebImage/SDWebImageTransformer.m | 179 ++++++++++-------- SDWebImage/UIImage+Transform.h | 6 +- .../project.pbxproj | 6 + Tests/Tests/SDCategoriesTests.m | 118 ------------ Tests/Tests/SDWebImageTransformerTests.m | 168 ++++++++++++++++ 6 files changed, 302 insertions(+), 209 deletions(-) create mode 100644 Tests/Tests/SDWebImageTransformerTests.m diff --git a/SDWebImage/SDWebImageTransformer.h b/SDWebImage/SDWebImageTransformer.h index 624bbe4d..31c126d7 100644 --- a/SDWebImage/SDWebImageTransformer.h +++ b/SDWebImage/SDWebImageTransformer.h @@ -48,18 +48,18 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab #pragma mark - Pipeline // Pipeline transformer. Which you can bind multiple transformers together to let the image to be transformed one by one in order and generate the final image. +// Because transformers are lightweight, if you want to append or arrange transfomers, create another pipeline transformer instead. This class is considered as immutable. @interface SDWebImagePipelineTransformer : NSObject @property (nonatomic, copy, readonly, nonnull) NSArray> *transformers; -- (nonnull instancetype)initWithTransformers:(nonnull NSArray> *)transformers; - -- (void)addTransformer:(nonnull id)transformer; -- (void)removeTransformer:(nonnull id)transformer; +- (nonnull instancetype)init NS_UNAVAILABLE; ++ (nonnull instancetype)transformerWithTransformers:(nonnull NSArray> *)transformers; @end -// There are some build-in transformer based on the `UIImage+Transformer` category to provide the common image geometry, image blending and image effect process. Those transform are useful for static image only but you can create your own to support animated image as well. +// There are some built-in transformers based on the `UIImage+Transformer` category to provide the common image geometry, image blending and image effect process. Those transform are useful for static image only but you can create your own to support animated image as well. +// Because transformers are lightweight, these class are considered as immutable. #pragma mark - Image Geometry // Image round corner transformer @@ -70,7 +70,8 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab @property (nonatomic, assign, readonly) CGFloat borderWidth; @property (nonatomic, strong, readonly, nullable) UIColor *borderColor; -- (nonnull instancetype)initWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(nullable UIColor *)borderColor; +- (nonnull instancetype)init NS_UNAVAILABLE; ++ (nonnull instancetype)transformerWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(nullable UIColor *)borderColor; @end @@ -80,7 +81,8 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab @property (nonatomic, assign, readonly) CGSize size; @property (nonatomic, assign, readonly) SDImageScaleMode scaleMode; -- (nonnull instancetype)initWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode; +- (nonnull instancetype)init NS_UNAVAILABLE; ++ (nonnull instancetype)transformerWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode; @end @@ -89,7 +91,8 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab @property (nonatomic, assign, readonly) CGRect rect; -- (nonnull instancetype)initWithRect:(CGRect)rect; +- (nonnull instancetype)init NS_UNAVAILABLE; ++ (nonnull instancetype)transformerWithRect:(CGRect)rect; @end @@ -99,7 +102,8 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab @property (nonatomic, assign, readonly) BOOL horizontal; @property (nonatomic, assign, readonly) BOOL vertical; -- (nonnull instancetype)initWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical; +- (nonnull instancetype)init NS_UNAVAILABLE; ++ (nonnull instancetype)transformerWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical; @end @@ -109,7 +113,8 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab @property (nonatomic, assign, readonly) CGFloat angle; @property (nonatomic, assign, readonly) BOOL fitSize; -- (nonnull instancetype)initWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize; +- (nonnull instancetype)init NS_UNAVAILABLE; ++ (nonnull instancetype)transformerWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize; @end @@ -120,7 +125,8 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab @property (nonatomic, strong, readonly, nonnull) UIColor *tintColor; -- (nonnull instancetype)initWithColor:(nonnull UIColor *)tintColor; +- (nonnull instancetype)init NS_UNAVAILABLE; ++ (nonnull instancetype)transformerWithColor:(nonnull UIColor *)tintColor; @end @@ -131,7 +137,8 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab @property (nonatomic, assign, readonly) CGFloat blurRadius; -- (nonnull instancetype)initWithRadius:(CGFloat)blurRadius; +- (nonnull instancetype)init NS_UNAVAILABLE; ++ (nonnull instancetype)transformerWithRadius:(CGFloat)blurRadius; @end @@ -141,7 +148,8 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab @property (nonatomic, strong, readonly, nonnull) CIFilter *filter; -- (nonnull instancetype)initWithFilter:(nonnull CIFilter *)filter; +- (nonnull instancetype)init NS_UNAVAILABLE; ++ (nonnull instancetype)transformerWithFilter:(nonnull CIFilter *)filter; @end #endif diff --git a/SDWebImage/SDWebImageTransformer.m b/SDWebImage/SDWebImageTransformer.m index 80ca3394..740ff09e 100644 --- a/SDWebImage/SDWebImageTransformer.m +++ b/SDWebImage/SDWebImageTransformer.m @@ -72,13 +72,12 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * @implementation SDWebImagePipelineTransformer -- (instancetype)initWithTransformers:(NSArray> *)transformers { - self = [super init]; - if (self) { - _transformers = [transformers copy]; - _transformerKey = [[self class] cacheKeyForTransformers:transformers]; - } - return self; ++ (instancetype)transformerWithTransformers:(NSArray> *)transformers { + SDWebImagePipelineTransformer *transformer = [SDWebImagePipelineTransformer new]; + transformer.transformers = transformers; + transformer.transformerKey = [[self class] cacheKeyForTransformers:transformers]; + + return transformer; } + (NSString *)cacheKeyForTransformers:(NSArray> *)transformers { @@ -105,35 +104,27 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * return transformedImage; } -- (void)addTransformer:(id)transformer { - if (!transformer) { - return; - } - self.transformers = [self.transformers arrayByAddingObject:transformer]; -} +@end -- (void)removeTransformer:(id)transformer { - if (!transformer) { - return; - } - NSMutableArray> *transformers = [self.transformers mutableCopy]; - [transformers removeObject:transformer]; - self.transformers = [transformers copy]; -} +@interface SDWebImageRoundCornerTransformer () + +@property (nonatomic, assign) CGFloat cornerRadius; +@property (nonatomic, assign) SDRectCorner corners; +@property (nonatomic, assign) CGFloat borderWidth; +@property (nonatomic, strong, nullable) UIColor *borderColor; @end @implementation SDWebImageRoundCornerTransformer -- (instancetype)initWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(nullable UIColor *)borderColor { - self = [super init]; - if (self) { - _cornerRadius = cornerRadius; - _corners = corners; - _borderWidth = borderWidth; - _borderColor = borderColor; - } - return self; ++ (instancetype)transformerWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor { + SDWebImageRoundCornerTransformer *transformer = [SDWebImageRoundCornerTransformer new]; + transformer.cornerRadius = cornerRadius; + transformer.corners = corners; + transformer.borderWidth = borderWidth; + transformer.borderColor = borderColor; + + return transformer; } - (NSString *)transformerKey { @@ -149,15 +140,21 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * @end +@interface SDWebImageResizingTransformer () + +@property (nonatomic, assign) CGSize size; +@property (nonatomic, assign) SDImageScaleMode scaleMode; + +@end + @implementation SDWebImageResizingTransformer -- (instancetype)initWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode { - self = [super init]; - if (self) { - _size = size; - _scaleMode = scaleMode; - } - return self; ++ (instancetype)transformerWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode { + SDWebImageResizingTransformer *transformer = [SDWebImageResizingTransformer new]; + transformer.size = size; + transformer.scaleMode = scaleMode; + + return transformer; } - (NSString *)transformerKey { @@ -174,14 +171,19 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * @end +@interface SDWebImageCroppingTransformer () + +@property (nonatomic, assign) CGRect rect; + +@end + @implementation SDWebImageCroppingTransformer -- (instancetype)initWithRect:(CGRect)rect { - self = [super init]; - if (self) { - _rect = rect; - } - return self; ++ (instancetype)transformerWithRect:(CGRect)rect { + SDWebImageCroppingTransformer *transformer = [SDWebImageCroppingTransformer new]; + transformer.rect = rect; + + return transformer; } - (NSString *)transformerKey { @@ -198,15 +200,21 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * @end +@interface SDWebImageFlippingTransformer () + +@property (nonatomic, assign) BOOL horizontal; +@property (nonatomic, assign) BOOL vertical; + +@end + @implementation SDWebImageFlippingTransformer -- (instancetype)initWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical { - self = [super init]; - if (self) { - _horizontal = horizontal; - _vertical = vertical; - } - return self; ++ (instancetype)transformerWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical { + SDWebImageFlippingTransformer *transformer = [SDWebImageFlippingTransformer new]; + transformer.horizontal = horizontal; + transformer.vertical = vertical; + + return transformer; } - (NSString *)transformerKey { @@ -222,15 +230,21 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * @end +@interface SDWebImageRotationTransformer () + +@property (nonatomic, assign) CGFloat angle; +@property (nonatomic, assign) BOOL fitSize; + +@end + @implementation SDWebImageRotationTransformer -- (instancetype)initWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize { - self = [super init]; - if (self) { - _angle = angle; - _fitSize = fitSize; - } - return self; ++ (instancetype)transformerWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize { + SDWebImageRotationTransformer *transformer = [SDWebImageRotationTransformer new]; + transformer.angle = angle; + transformer.fitSize = fitSize; + + return transformer; } - (NSString *)transformerKey { @@ -248,14 +262,19 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * #pragma mark - Image Blending +@interface SDWebImageTintTransformer () + +@property (nonatomic, strong, nonnull) UIColor *tintColor; + +@end + @implementation SDWebImageTintTransformer -- (instancetype)initWithColor:(UIColor *)tintColor { - self = [super init]; - if (self) { - _tintColor = tintColor; - } - return self; ++ (instancetype)transformerWithColor:(UIColor *)tintColor { + SDWebImageTintTransformer *transformer = [SDWebImageTintTransformer new]; + transformer.tintColor = tintColor; + + return transformer; } - (NSString *)transformerKey { @@ -273,14 +292,19 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * #pragma mark - Image Effect +@interface SDWebImageBlurTransformer () + +@property (nonatomic, assign) CGFloat blurRadius; + +@end + @implementation SDWebImageBlurTransformer -- (instancetype)initWithRadius:(CGFloat)blurRadius { - self = [super init]; - if (self) { - _blurRadius = blurRadius; - } - return self; ++ (instancetype)transformerWithRadius:(CGFloat)blurRadius { + SDWebImageBlurTransformer *transformer = [SDWebImageBlurTransformer new]; + transformer.blurRadius = blurRadius; + + return transformer; } - (NSString *)transformerKey { @@ -297,14 +321,19 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * @end #if SD_UIKIT || SD_MAC +@interface SDWebImageFilterTransformer () + +@property (nonatomic, strong, nonnull) CIFilter *filter; + +@end + @implementation SDWebImageFilterTransformer -- (instancetype)initWithFilter:(CIFilter *)filter { - self = [super init]; - if (self) { - _filter = filter; - } - return self; ++ (instancetype)transformerWithFilter:(CIFilter *)filter { + SDWebImageFilterTransformer *transformer = [SDWebImageFilterTransformer new]; + transformer.filter = filter; + + return transformer; } - (NSString *)transformerKey { diff --git a/SDWebImage/UIImage+Transform.h b/SDWebImage/UIImage+Transform.h index ff999bba..717c08cc 100644 --- a/SDWebImage/UIImage+Transform.h +++ b/SDWebImage/UIImage+Transform.h @@ -35,10 +35,10 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { #pragma mark - Image Geometry /** - Returns a new image which is scaled from this image. - The image content will be changed with the scale mode. + Returns a new image which is resized from this image. + You can specify a larger or smaller size than the image size. The image content will be changed with the scale mode. - @param size The new size to be scaled, values should be positive. + @param size The new size to be resized, values should be positive. @param scaleMode The scale mode for image content. @return The new image with the given size. */ diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 790c3e7e..5ce63173 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -12,6 +12,8 @@ 2D7AF0601F329763000083C2 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; }; 321259EC1F39E3240096FE0E /* TestImageStatic.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259EB1F39E3240096FE0E /* TestImageStatic.webp */; }; 321259EE1F39E4110096FE0E /* TestImageAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */; }; + 3254C32020641077008D1022 /* SDWebImageTransformerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */; }; + 3254C32120641077008D1022 /* SDWebImageTransformerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */; }; 3264FF2F205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */; }; 3264FF30205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */; }; 32B99E8B203AF8690017FD66 /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */; }; @@ -58,6 +60,7 @@ 2D7AF05F1F329763000083C2 /* SDTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDTestCase.m; sourceTree = ""; }; 321259EB1F39E3240096FE0E /* TestImageStatic.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageStatic.webp; sourceTree = ""; }; 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageAnimated.webp; sourceTree = ""; }; + 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransformerTests.m; sourceTree = ""; }; 3264FF2D205D42CB00F6BD48 /* SDWebImageTestTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestTransformer.h; sourceTree = ""; }; 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestTransformer.m; sourceTree = ""; }; 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDCategoriesTests.m; sourceTree = ""; }; @@ -189,6 +192,7 @@ 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */, 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */, 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */, + 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */, 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */, 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */, 37D122861EC48B5E00D98CEB /* SDMockFileManager.h */, @@ -445,6 +449,7 @@ buildActionMask = 2147483647; files = ( 32B99EAC203B36650017FD66 /* SDWebImageDownloaderTests.m in Sources */, + 3254C32120641077008D1022 /* SDWebImageTransformerTests.m in Sources */, 32B99E9C203B2EE40017FD66 /* SDCategoriesTests.m in Sources */, 32B99EAA203B365F0017FD66 /* SDImageCacheTests.m in Sources */, 32B99EAD203B36690017FD66 /* SDWebImagePrefetcherTests.m in Sources */, @@ -463,6 +468,7 @@ buildActionMask = 2147483647; files = ( 32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */, + 3254C32020641077008D1022 /* SDWebImageTransformerTests.m in Sources */, 1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */, 37D122881EC48B5E00D98CEB /* SDMockFileManager.m in Sources */, 4369C2741D9804B1007E863A /* SDWebCacheCategoriesTests.m in Sources */, diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m index 0d00aa09..b49378ed 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDCategoriesTests.m @@ -15,20 +15,9 @@ #import #import #import -#import -#import - -// Internal header -@interface UIColor (HexString) - -@property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString; - -@end @interface SDCategoriesTests : SDTestCase -@property (nonatomic, strong) UIImage *testImage; - @end @implementation SDCategoriesTests @@ -76,110 +65,8 @@ expect(image).notTo.beNil(); } -// UIImage+Transform test is hard to write because it's more about visual effect. Current it's tied to the `TestImage.png`, please keep that image or write new test with new image -- (void)test05UIImageTransformResize { - CGSize size = CGSizeMake(200, 100); - UIImage *resizedImage = [self.testImage sd_resizedImageWithSize:size scaleMode:SDImageScaleModeFill]; - expect(CGSizeEqualToSize(resizedImage.size, size)).beTruthy(); -} - -- (void)test06UIImageTransformCrop { - CGRect rect = CGRectMake(50, 50, 200, 200); - UIImage *croppedImage = [self.testImage sd_croppedImageWithRect:rect]; - expect(CGSizeEqualToSize(croppedImage.size, CGSizeMake(200, 200))).beTruthy(); - UIColor *startColor = [croppedImage sd_colorAtPoint:CGPointZero]; - expect([startColor.sd_hexString isEqualToString:[UIColor clearColor].sd_hexString]).beTruthy(); -} - -- (void)test07UIImageTransformRoundedCorner { - CGFloat radius = 50; -#if SD_UIKIT - SDRectCorner corners = UIRectCornerAllCorners; -#else - SDRectCorner corners = SDRectCornerAllCorners; -#endif - CGFloat borderWidth = 1; - UIColor *borderCoder = [UIColor blackColor]; - UIImage *roundedCornerImage = [self.testImage sd_roundedCornerImageWithRadius:radius corners:corners borderWidth:borderWidth borderColor:borderCoder]; - expect(CGSizeEqualToSize(roundedCornerImage.size, CGSizeMake(300, 300))).beTruthy(); - UIColor *startColor = [roundedCornerImage sd_colorAtPoint:CGPointZero]; - expect([startColor.sd_hexString isEqualToString:[UIColor clearColor].sd_hexString]).beTruthy(); - // Check the left center pixel, should be border :) - UIColor *checkBorderColor = [roundedCornerImage sd_colorAtPoint:CGPointMake(1, 150)]; - expect([checkBorderColor.sd_hexString isEqualToString:borderCoder.sd_hexString]).beTruthy(); -} - -- (void)test08UIImageTransformRotate { - CGFloat angle = M_PI_4; - UIImage *rotatedImage = [self.testImage sd_rotatedImageWithAngle:angle fitSize:NO]; - // Not fit size and no change - expect(CGSizeEqualToSize(rotatedImage.size, self.testImage.size)).beTruthy(); - // Fit size, may change size - rotatedImage = [self.testImage sd_rotatedImageWithAngle:angle fitSize:YES]; - CGSize rotatedSize = CGSizeMake(floor(300 * 1.414), floor(300 * 1.414)); // 45º, square length * sqrt(2) - expect(CGSizeEqualToSize(rotatedImage.size, rotatedSize)).beTruthy(); - rotatedImage = [self.testImage sd_rotatedImageWithAngle:angle fitSize:NO]; -} - -- (void)test09UIImageTransformFlip { - BOOL horizontal = YES; - BOOL vertical = YES; - UIImage *flippedImage = [self.testImage sd_flippedImageWithHorizontal:horizontal vertical:vertical]; - expect(CGSizeEqualToSize(flippedImage.size, self.testImage.size)).beTruthy(); - // Test pixel colors method here - UIColor *checkColor = [flippedImage sd_colorAtPoint:CGPointMake(75, 75)]; - expect(checkColor); - NSArray *checkColors = [flippedImage sd_colorsWithRect:CGRectMake(75, 75, 10, 10)]; // Rect are all same color - expect(checkColors.count).to.equal(10 * 10); - for (UIColor *color in checkColors) { - expect([color isEqual:checkColor]).to.beTruthy(); - } -} - -- (void)test10UIImageTransformTint { - UIColor *tintColor = [UIColor blackColor]; - UIImage *tintedImage = [self.testImage sd_tintedImageWithColor:tintColor]; - expect(CGSizeEqualToSize(tintedImage.size, self.testImage.size)).beTruthy(); - // Check center color, should keep clear - UIColor *centerColor = [tintedImage sd_colorAtPoint:CGPointMake(150, 150)]; - expect([centerColor.sd_hexString isEqualToString:[UIColor clearColor].sd_hexString]); - // Check left color, should be tinted - UIColor *leftColor = [tintedImage sd_colorAtPoint:CGPointMake(80, 150)]; - expect([leftColor.sd_hexString isEqualToString:tintColor.sd_hexString]); -} - -- (void)test11UIImageTransformBlur { - CGFloat radius = 50; - UIImage *blurredImage = [self.testImage sd_blurredImageWithRadius:radius]; - expect(CGSizeEqualToSize(blurredImage.size, self.testImage.size)).beTruthy(); - // Check left color, should be blurred - UIColor *leftColor = [blurredImage sd_colorAtPoint:CGPointMake(80, 150)]; - // Hard-code from the output - UIColor *expectedColor = [UIColor colorWithRed:0.431373 green:0.101961 blue:0.0901961 alpha:0.729412]; - expect([leftColor.sd_hexString isEqualToString:expectedColor.sd_hexString]); -} - -- (void)test12UIImageTransformFilter { - // Invert color filter - CIFilter *filter = [CIFilter filterWithName:@"CIColorInvert"]; - UIImage *filteredImage = [self.testImage sd_filteredImageWithFilter:filter]; - expect(CGSizeEqualToSize(filteredImage.size, self.testImage.size)).beTruthy(); - // Check left color, should be inverted - UIColor *leftColor = [filteredImage sd_colorAtPoint:CGPointMake(80, 150)]; - // Hard-code from the output - UIColor *expectedColor = [UIColor colorWithRed:0.85098 green:0.992157 blue:0.992157 alpha:1]; - expect([leftColor.sd_hexString isEqualToString:expectedColor.sd_hexString]); -} - #pragma mark - Helper -- (UIImage *)testImage { - if (!_testImage) { - _testImage = [[UIImage alloc] initWithContentsOfFile:[self testPNGPath]]; - } - return _testImage; -} - - (NSString *)testJPEGPath { NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; return [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; @@ -195,9 +82,4 @@ return [testBundle pathForResource:@"TestImageStatic" ofType:@"webp"]; } -- (NSString *)testPNGPath { - NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; - return [testBundle pathForResource:@"TestImage" ofType:@"png"]; -} - @end diff --git a/Tests/Tests/SDWebImageTransformerTests.m b/Tests/Tests/SDWebImageTransformerTests.m new file mode 100644 index 00000000..feff0241 --- /dev/null +++ b/Tests/Tests/SDWebImageTransformerTests.m @@ -0,0 +1,168 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Matt Galloway + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDTestCase.h" +#import +#import +#import + +// Internal header +@interface UIColor (HexString) + +@property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString; + +@end + +@interface SDWebImageTransformerTests : SDTestCase + +@property (nonatomic, strong) UIImage *testImage; + +@end + +@implementation SDWebImageTransformerTests + +#pragma mark - UIImage+Transform + +// UIImage+Transform test is hard to write because it's more about visual effect. Current it's tied to the `TestImage.png`, please keep that image or write new test with new image +- (void)test01UIImageTransformResize { + CGSize scaleDownSize = CGSizeMake(200, 100); + UIImage *scaledDownImage = [self.testImage sd_resizedImageWithSize:scaleDownSize scaleMode:SDImageScaleModeFill]; + expect(CGSizeEqualToSize(scaledDownImage.size, scaleDownSize)).beTruthy(); + CGSize scaleUpSize = CGSizeMake(2000, 1000); + UIImage *scaledUpImage = [self.testImage sd_resizedImageWithSize:scaleUpSize scaleMode:SDImageScaleModeAspectFit]; + expect(CGSizeEqualToSize(scaledUpImage.size, scaleUpSize)).beTruthy(); +} + +- (void)test02UIImageTransformCrop { + CGRect rect = CGRectMake(50, 50, 200, 200); + UIImage *croppedImage = [self.testImage sd_croppedImageWithRect:rect]; + expect(CGSizeEqualToSize(croppedImage.size, CGSizeMake(200, 200))).beTruthy(); + UIColor *startColor = [croppedImage sd_colorAtPoint:CGPointZero]; + expect([startColor.sd_hexString isEqualToString:[UIColor clearColor].sd_hexString]).beTruthy(); +} + +- (void)test03UIImageTransformRoundedCorner { + CGFloat radius = 50; +#if SD_UIKIT + SDRectCorner corners = UIRectCornerAllCorners; +#else + SDRectCorner corners = SDRectCornerAllCorners; +#endif + CGFloat borderWidth = 1; + UIColor *borderColor = [UIColor blackColor]; + UIImage *roundedCornerImage = [self.testImage sd_roundedCornerImageWithRadius:radius corners:corners borderWidth:borderWidth borderColor:borderColor]; + expect(CGSizeEqualToSize(roundedCornerImage.size, CGSizeMake(300, 300))).beTruthy(); + UIColor *startColor = [roundedCornerImage sd_colorAtPoint:CGPointZero]; + expect([startColor.sd_hexString isEqualToString:[UIColor clearColor].sd_hexString]).beTruthy(); + // Check the left center pixel, should be border :) + UIColor *checkBorderColor = [roundedCornerImage sd_colorAtPoint:CGPointMake(1, 150)]; + expect([checkBorderColor.sd_hexString isEqualToString:borderColor.sd_hexString]).beTruthy(); +} + +- (void)test04UIImageTransformRotate { + CGFloat angle = M_PI_4; + UIImage *rotatedImage = [self.testImage sd_rotatedImageWithAngle:angle fitSize:NO]; + // Not fit size and no change + expect(CGSizeEqualToSize(rotatedImage.size, self.testImage.size)).beTruthy(); + // Fit size, may change size + rotatedImage = [self.testImage sd_rotatedImageWithAngle:angle fitSize:YES]; + CGSize rotatedSize = CGSizeMake(floor(300 * 1.414), floor(300 * 1.414)); // 45º, square length * sqrt(2) + expect(CGSizeEqualToSize(rotatedImage.size, rotatedSize)).beTruthy(); + rotatedImage = [self.testImage sd_rotatedImageWithAngle:angle fitSize:NO]; +} + +- (void)test05UIImageTransformFlip { + BOOL horizontal = YES; + BOOL vertical = YES; + UIImage *flippedImage = [self.testImage sd_flippedImageWithHorizontal:horizontal vertical:vertical]; + expect(CGSizeEqualToSize(flippedImage.size, self.testImage.size)).beTruthy(); + // Test pixel colors method here + UIColor *checkColor = [flippedImage sd_colorAtPoint:CGPointMake(75, 75)]; + expect(checkColor); + NSArray *checkColors = [flippedImage sd_colorsWithRect:CGRectMake(75, 75, 10, 10)]; // Rect are all same color + expect(checkColors.count).to.equal(10 * 10); + for (UIColor *color in checkColors) { + expect([color isEqual:checkColor]).to.beTruthy(); + } +} + +- (void)test06UIImageTransformTint { + UIColor *tintColor = [UIColor blackColor]; + UIImage *tintedImage = [self.testImage sd_tintedImageWithColor:tintColor]; + expect(CGSizeEqualToSize(tintedImage.size, self.testImage.size)).beTruthy(); + // Check center color, should keep clear + UIColor *centerColor = [tintedImage sd_colorAtPoint:CGPointMake(150, 150)]; + expect([centerColor.sd_hexString isEqualToString:[UIColor clearColor].sd_hexString]); + // Check left color, should be tinted + UIColor *leftColor = [tintedImage sd_colorAtPoint:CGPointMake(80, 150)]; + expect([leftColor.sd_hexString isEqualToString:tintColor.sd_hexString]); +} + +- (void)test07UIImageTransformBlur { + CGFloat radius = 50; + UIImage *blurredImage = [self.testImage sd_blurredImageWithRadius:radius]; + expect(CGSizeEqualToSize(blurredImage.size, self.testImage.size)).beTruthy(); + // Check left color, should be blurred + UIColor *leftColor = [blurredImage sd_colorAtPoint:CGPointMake(80, 150)]; + // Hard-code from the output + UIColor *expectedColor = [UIColor colorWithRed:0.431373 green:0.101961 blue:0.0901961 alpha:0.729412]; + expect([leftColor.sd_hexString isEqualToString:expectedColor.sd_hexString]); +} + +- (void)test08UIImageTransformFilter { + // Invert color filter + CIFilter *filter = [CIFilter filterWithName:@"CIColorInvert"]; + UIImage *filteredImage = [self.testImage sd_filteredImageWithFilter:filter]; + expect(CGSizeEqualToSize(filteredImage.size, self.testImage.size)).beTruthy(); + // Check left color, should be inverted + UIColor *leftColor = [filteredImage sd_colorAtPoint:CGPointMake(80, 150)]; + // Hard-code from the output + UIColor *expectedColor = [UIColor colorWithRed:0.85098 green:0.992157 blue:0.992157 alpha:1]; + expect([leftColor.sd_hexString isEqualToString:expectedColor.sd_hexString]); +} + +#pragma mark - SDWebImageTransformer + +- (void)test09ImagePipelineTransformer { + CGSize size = CGSizeMake(100, 100); + SDImageScaleMode scaleMode = SDImageScaleModeAspectFill; + CGFloat angle = M_PI_4; + BOOL fitSize = NO; + CGFloat radius = 50; +#if SD_UIKIT + SDRectCorner corners = UIRectCornerAllCorners; +#else + SDRectCorner corners = SDRectCornerAllCorners; +#endif + CGFloat borderWidth = 1; + UIColor *borderCoder = [UIColor blackColor]; + SDWebImageResizingTransformer *transformer1 = [SDWebImageResizingTransformer transformerWithSize:size scaleMode:scaleMode]; + SDWebImageRotationTransformer *transformer2 = [SDWebImageRotationTransformer transformerWithAngle:angle fitSize:fitSize]; + SDWebImageRoundCornerTransformer *transformer3 = [SDWebImageRoundCornerTransformer transformerWithRadius:radius corners:corners borderWidth:borderWidth borderColor:borderCoder]; + SDWebImagePipelineTransformer *pipelineTransformer = [SDWebImagePipelineTransformer transformerWithTransformers:@[transformer1, transformer2, transformer3]]; + + UIImage *transformedImage = [pipelineTransformer transformedImageWithImage:self.testImage forKey:@"Test"]; + expect(CGSizeEqualToSize(transformedImage.size, size)).beTruthy(); +} + +#pragma mark - Helper + +- (UIImage *)testImage { + if (!_testImage) { + _testImage = [[UIImage alloc] initWithContentsOfFile:[self testPNGPath]]; + } + return _testImage; +} + +- (NSString *)testPNGPath { + NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; + return [testBundle pathForResource:@"TestImage" ofType:@"png"]; +} + +@end From 1c8205b17d78df8fd0afa747f7a7d69c8298b1d5 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 24 Mar 2018 20:29:05 +0800 Subject: [PATCH 061/361] Use a weak pointer array to avoid prefetch token strong reference to the operation. And fix the thread-safe problem. --- SDWebImage/SDWebImagePrefetcher.h | 8 ++++++++ SDWebImage/SDWebImagePrefetcher.m | 18 +++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/SDWebImage/SDWebImagePrefetcher.h b/SDWebImage/SDWebImagePrefetcher.h index cba81edf..9ae1678a 100644 --- a/SDWebImage/SDWebImagePrefetcher.h +++ b/SDWebImage/SDWebImagePrefetcher.h @@ -13,6 +13,14 @@ @interface SDWebImagePrefetchToken : NSObject +/** + * Cancel the current prefeching. + */ +- (void)cancel; + +/** + list of URLs of current prefetching. + */ @property (nonatomic, copy, readonly, nullable) NSArray *urls; @end diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index d8133403..dfb82a10 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -17,7 +17,7 @@ @property (nonatomic, copy, readwrite) NSArray *urls; @property (nonatomic, assign) int64_t totalCount; -@property (nonatomic, strong) NSMutableArray> *operations; +@property (nonatomic, strong) NSPointerArray *operations; @property (nonatomic, weak) SDWebImagePrefetcher *prefetcher; @property (nonatomic, copy, nullable) SDWebImagePrefetcherCompletionBlock completionBlock; @property (nonatomic, copy, nullable) SDWebImagePrefetcherProgressBlock progressBlock; @@ -85,11 +85,12 @@ token->_finishedCount = 0; token.urls = urls; token.totalCount = urls.count; - token.operations = [NSMutableArray arrayWithCapacity:urls.count]; + token.operations = [NSPointerArray weakObjectsPointerArray]; token.progressBlock = progressBlock; token.completionBlock = completionBlock; [self addRunningToken:token]; + NSPointerArray *operations = token.operations; for (NSURL *url in urls) { __weak typeof(self) wself = self; id operation = [self.manager loadImageWithURL:url options:self.options progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { @@ -115,7 +116,9 @@ [sself removeRunningToken:token]; } } context:self.context]; - [token.operations addObject:operation]; + @synchronized (token) { + [operations addPointer:(__bridge void *)operation]; + } } return token; @@ -223,10 +226,15 @@ - (void)cancel { @synchronized (self) { - for (id operation in self.operations) { - [operation cancel]; + for (id operation in self.operations) { + if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) { + [operation cancel]; + } } + self.operations.count = 0; } + self.completionBlock = nil; + self.progressBlock = nil; [self.prefetcher removeRunningToken:self]; } From 87bbcdc46ff8857aaebbfbc663c340a351a80a58 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 21 Dec 2017 11:43:46 +0800 Subject: [PATCH 062/361] Introduce SDAnimatedImage and SDAnimatedImageView for high performance animated image rendering on iOS & macOS --- .../SDWebImage Demo/DetailViewController.m | 4 +- .../SDWebImage Demo/MasterViewController.m | 6 +- .../en.lproj/DetailViewController.xib | 14 +- .../Base.lproj/Main.storyboard | 4 +- Examples/SDWebImage OSX Demo/ViewController.m | 20 +- .../Base.lproj/Main.storyboard | 33 +- Examples/SDWebImage TV Demo/ViewController.m | 17 +- SDWebImage.xcodeproj/project.pbxproj | 92 +++ SDWebImage/SDAnimatedImage.h | 66 ++ SDWebImage/SDAnimatedImage.m | 167 ++++ SDWebImage/SDAnimatedImageView+WebCache.h | 126 +++ SDWebImage/SDAnimatedImageView+WebCache.m | 57 ++ SDWebImage/SDAnimatedImageView.h | 59 ++ SDWebImage/SDAnimatedImageView.m | 757 ++++++++++++++++++ SDWebImage/SDImageCache.m | 9 +- SDWebImage/SDWebImageCoder.h | 75 +- SDWebImage/SDWebImageCoder.m | 23 +- SDWebImage/SDWebImageCoderHelper.h | 56 +- SDWebImage/SDWebImageCoderHelper.m | 303 ++++++- SDWebImage/SDWebImageCodersManager.m | 35 +- SDWebImage/SDWebImageDownloaderOperation.m | 19 +- SDWebImage/SDWebImageGIFCoder.h | 7 +- SDWebImage/SDWebImageGIFCoder.m | 173 +++- SDWebImage/SDWebImageImageIOCoder.m | 321 +------- SDWebImage/SDWebImageWebPCoder.h | 2 +- SDWebImage/SDWebImageWebPCoder.m | 372 +++++++-- SDWebImage/UIImage+ForceDecode.m | 8 +- SDWebImage/UIImage+GIF.m | 2 +- SDWebImage/UIImage+MultiFormat.m | 4 +- SDWebImage/UIImage+WebP.m | 2 +- Tests/Tests/SDWebImageDecoderTests.m | 4 +- Tests/Tests/SDWebImageDownloaderTests.m | 5 - Tests/Tests/SDWebImageTestDecoder.h | 2 +- Tests/Tests/SDWebImageTestDecoder.m | 22 +- WebImage/SDWebImage.h | 3 + 35 files changed, 2332 insertions(+), 537 deletions(-) create mode 100644 SDWebImage/SDAnimatedImage.h create mode 100644 SDWebImage/SDAnimatedImage.m create mode 100644 SDWebImage/SDAnimatedImageView+WebCache.h create mode 100644 SDWebImage/SDAnimatedImageView+WebCache.m create mode 100644 SDWebImage/SDAnimatedImageView.h create mode 100644 SDWebImage/SDAnimatedImageView.m diff --git a/Examples/SDWebImage Demo/DetailViewController.m b/Examples/SDWebImage Demo/DetailViewController.m index 9e9d4540..c2fc9ade 100644 --- a/Examples/SDWebImage Demo/DetailViewController.m +++ b/Examples/SDWebImage Demo/DetailViewController.m @@ -8,11 +8,11 @@ #import "DetailViewController.h" #import -#import +#import @interface DetailViewController () -@property (strong, nonatomic) IBOutlet FLAnimatedImageView *imageView; +@property (strong, nonatomic) IBOutlet SDAnimatedImageView *imageView; @end diff --git a/Examples/SDWebImage Demo/MasterViewController.m b/Examples/SDWebImage Demo/MasterViewController.m index 3758959f..669a71c4 100644 --- a/Examples/SDWebImage Demo/MasterViewController.m +++ b/Examples/SDWebImage Demo/MasterViewController.m @@ -8,13 +8,13 @@ #import "MasterViewController.h" #import "DetailViewController.h" -#import +#import #import @interface MyCustomTableViewCell : UITableViewCell @property (nonatomic, strong) UILabel *customTextLabel; -@property (nonatomic, strong) FLAnimatedImageView *customImageView; +@property (nonatomic, strong) SDAnimatedImageView *customImageView; @end @@ -22,7 +22,7 @@ - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { - _customImageView = [[FLAnimatedImageView alloc] initWithFrame:CGRectMake(20.0, 2.0, 60.0, 40.0)]; + _customImageView = [[SDAnimatedImageView alloc] initWithFrame:CGRectMake(20.0, 2.0, 60.0, 40.0)]; [self.contentView addSubview:_customImageView]; _customTextLabel = [[UILabel alloc] initWithFrame:CGRectMake(100.0, 12.0, 200, 20.0)]; [self.contentView addSubview:_customTextLabel]; diff --git a/Examples/SDWebImage Demo/en.lproj/DetailViewController.xib b/Examples/SDWebImage Demo/en.lproj/DetailViewController.xib index c3e3aad5..b7ad1179 100644 --- a/Examples/SDWebImage Demo/en.lproj/DetailViewController.xib +++ b/Examples/SDWebImage Demo/en.lproj/DetailViewController.xib @@ -1,8 +1,12 @@ - - + + + + + - + + @@ -16,12 +20,12 @@ - + - + diff --git a/Examples/SDWebImage OSX Demo/Base.lproj/Main.storyboard b/Examples/SDWebImage OSX Demo/Base.lproj/Main.storyboard index eaa4ae59..e4fce680 100644 --- a/Examples/SDWebImage OSX Demo/Base.lproj/Main.storyboard +++ b/Examples/SDWebImage OSX Demo/Base.lproj/Main.storyboard @@ -687,12 +687,12 @@ - + - + diff --git a/Examples/SDWebImage OSX Demo/ViewController.m b/Examples/SDWebImage OSX Demo/ViewController.m index d3d5e298..4d5d9b0d 100644 --- a/Examples/SDWebImage OSX Demo/ViewController.m +++ b/Examples/SDWebImage OSX Demo/ViewController.m @@ -7,6 +7,8 @@ */ #import "ViewController.h" +#import +#import @import SDWebImage; @@ -14,8 +16,8 @@ @property (weak) IBOutlet NSImageView *imageView1; @property (weak) IBOutlet NSImageView *imageView2; -@property (weak) IBOutlet NSImageView *imageView3; -@property (weak) IBOutlet NSImageView *imageView4; +@property (weak) IBOutlet SDAnimatedImageView *imageView3; +@property (weak) IBOutlet SDAnimatedImageView *imageView4; @property (weak) IBOutlet NSButton *clearCacheButton; @end @@ -25,22 +27,16 @@ - (void)viewDidLoad { [super viewDidLoad]; - //Add GIF coder for better animated image rendering - [[SDWebImageCodersManager sharedManager] addCoder:[SDWebImageGIFCoder sharedCoder]]; - - // NOTE: https links or authentication ones do not work (there is a crash) - -// Do any additional setup after loading the view. // For animated GIF rendering, set `animates` to YES or will only show the first frame - self.imageView1.animates = YES; self.imageView3.animates = YES; + self.imageView4.animates = YES; self.imageView1.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator; - [self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"http://assets.sbnation.com/assets/2512203/dogflops.gif"]]; + [self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"]]; [self.imageView2 sd_setImageWithURL:[NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp"]]; - [self.imageView3 sd_setImageWithURL:[NSURL URLWithString:@"http://littlesvr.ca/apng/images/SteamEngine.webp"]]; + [self.imageView3 sd_setImageWithURL:[NSURL URLWithString:@"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"]]; self.imageView4.wantsLayer = YES; self.imageView4.sd_imageTransition = SDWebImageTransition.fadeTransition; - [self.imageView4 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"] placeholderImage:nil options:SDWebImageForceTransition]; + [self.imageView4 sd_setImageWithURL:[NSURL URLWithString:@"http://littlesvr.ca/apng/images/SteamEngine.webp"] placeholderImage:nil options:SDWebImageForceTransition]; self.clearCacheButton.target = self; self.clearCacheButton.action = @selector(clearCacheButtonClicked:); diff --git a/Examples/SDWebImage TV Demo/Base.lproj/Main.storyboard b/Examples/SDWebImage TV Demo/Base.lproj/Main.storyboard index 91f4335d..5f902948 100644 --- a/Examples/SDWebImage TV Demo/Base.lproj/Main.storyboard +++ b/Examples/SDWebImage TV Demo/Base.lproj/Main.storyboard @@ -1,7 +1,12 @@ - - + + + + + - + + + @@ -16,20 +21,24 @@ - + + - - - - - - - + + + + + + + + + + - + diff --git a/Examples/SDWebImage TV Demo/ViewController.m b/Examples/SDWebImage TV Demo/ViewController.m index 2fb918e5..16f34316 100644 --- a/Examples/SDWebImage TV Demo/ViewController.m +++ b/Examples/SDWebImage TV Demo/ViewController.m @@ -7,14 +7,15 @@ */ #import "ViewController.h" -#import +#import +#import @interface ViewController () -@property (weak, nonatomic) IBOutlet FLAnimatedImageView *imageView1; -@property (weak, nonatomic) IBOutlet FLAnimatedImageView *imageView2; -@property (weak, nonatomic) IBOutlet FLAnimatedImageView *imageView3; -@property (weak, nonatomic) IBOutlet FLAnimatedImageView *imageView4; +@property (weak, nonatomic) IBOutlet UIImageView *imageView1; +@property (weak, nonatomic) IBOutlet UIImageView *imageView2; +@property (weak, nonatomic) IBOutlet SDAnimatedImageView *imageView3; +@property (weak, nonatomic) IBOutlet SDAnimatedImageView *imageView4; @end @@ -25,10 +26,10 @@ [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. - [self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"http://assets.sbnation.com/assets/2512203/dogflops.gif"]]; + [self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"]]; [self.imageView2 sd_setImageWithURL:[NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp"]]; - [self.imageView3 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage000.jpg"]]; - [self.imageView4 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"]]; + [self.imageView3 sd_setImageWithURL:[NSURL URLWithString:@"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"]]; + [self.imageView4 sd_setImageWithURL:[NSURL URLWithString:@"http://littlesvr.ca/apng/images/SteamEngine.webp"]]; } - (void)didReceiveMemoryWarning { diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 7d7389da..15054747 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -316,6 +316,42 @@ 323F8C1D1F38EF770092B609 /* muxread.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3D1F38EF770092B609 /* muxread.c */; }; 323F8C1E1F38EF770092B609 /* muxread.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3D1F38EF770092B609 /* muxread.c */; }; 323F8C1F1F38EF770092B609 /* muxread.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3D1F38EF770092B609 /* muxread.c */; }; + 3248475D201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; + 3248475E201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; + 3248475F201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; + 32484760201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; + 32484761201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; + 32484762201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; + 32484763201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32484764201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32484765201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32484766201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32484767201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32484768201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32484769201775F600AF9E5A /* SDAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484759201775F600AF9E5A /* SDAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3248476A201775F600AF9E5A /* SDAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484759201775F600AF9E5A /* SDAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3248476B201775F600AF9E5A /* SDAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484759201775F600AF9E5A /* SDAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3248476C201775F600AF9E5A /* SDAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484759201775F600AF9E5A /* SDAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3248476D201775F600AF9E5A /* SDAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484759201775F600AF9E5A /* SDAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3248476E201775F600AF9E5A /* SDAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484759201775F600AF9E5A /* SDAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3248476F201775F600AF9E5A /* SDAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475A201775F600AF9E5A /* SDAnimatedImage.m */; }; + 32484770201775F600AF9E5A /* SDAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475A201775F600AF9E5A /* SDAnimatedImage.m */; }; + 32484771201775F600AF9E5A /* SDAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475A201775F600AF9E5A /* SDAnimatedImage.m */; }; + 32484772201775F600AF9E5A /* SDAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475A201775F600AF9E5A /* SDAnimatedImage.m */; }; + 32484773201775F600AF9E5A /* SDAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475A201775F600AF9E5A /* SDAnimatedImage.m */; }; + 32484774201775F600AF9E5A /* SDAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475A201775F600AF9E5A /* SDAnimatedImage.m */; }; + 32484775201775F600AF9E5A /* SDAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3248475B201775F600AF9E5A /* SDAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32484776201775F600AF9E5A /* SDAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3248475B201775F600AF9E5A /* SDAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32484777201775F600AF9E5A /* SDAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3248475B201775F600AF9E5A /* SDAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32484778201775F600AF9E5A /* SDAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3248475B201775F600AF9E5A /* SDAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32484779201775F600AF9E5A /* SDAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3248475B201775F600AF9E5A /* SDAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3248477A201775F600AF9E5A /* SDAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3248475B201775F600AF9E5A /* SDAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3248477B201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */; }; + 3248477C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */; }; + 3248477D201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */; }; + 3248477E201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */; }; + 3248477F201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */; }; + 32484780201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */; }; 324DF4B4200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; 324DF4B5200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; 324DF4B6200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1403,6 +1439,12 @@ 323F8B3B1F38EF770092B609 /* muxi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = muxi.h; sourceTree = ""; }; 323F8B3C1F38EF770092B609 /* muxinternal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = muxinternal.c; sourceTree = ""; }; 323F8B3D1F38EF770092B609 /* muxread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = muxread.c; sourceTree = ""; }; + 32484757201775F600AF9E5A /* SDAnimatedImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImageView.m; sourceTree = ""; }; + 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SDAnimatedImageView+WebCache.h"; sourceTree = ""; }; + 32484759201775F600AF9E5A /* SDAnimatedImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDAnimatedImageView.h; sourceTree = ""; }; + 3248475A201775F600AF9E5A /* SDAnimatedImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImage.m; sourceTree = ""; }; + 3248475B201775F600AF9E5A /* SDAnimatedImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDAnimatedImage.h; sourceTree = ""; }; + 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SDAnimatedImageView+WebCache.m"; sourceTree = ""; }; 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDefine.h; sourceTree = ""; }; 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDefine.m; sourceTree = ""; }; 325312C6200F09910046BF1E /* SDWebImageTransition.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTransition.h; sourceTree = ""; }; @@ -1720,6 +1762,19 @@ path = mux; sourceTree = ""; }; + 32484756201775CE00AF9E5A /* ImageView */ = { + isa = PBXGroup; + children = ( + 3248475B201775F600AF9E5A /* SDAnimatedImage.h */, + 3248475A201775F600AF9E5A /* SDAnimatedImage.m */, + 32484759201775F600AF9E5A /* SDAnimatedImageView.h */, + 32484757201775F600AF9E5A /* SDAnimatedImageView.m */, + 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */, + 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */, + ); + name = ImageView; + sourceTree = ""; + }; 4369C2851D9811BB007E863A /* WebCache Categories */ = { isa = PBXGroup; children = ( @@ -1842,6 +1897,7 @@ 53922DAB148C56810056699D /* Downloader */, 53922DAA148C56470056699D /* Cache */, 321E60831F38E88F00405457 /* Decoder */, + 32484756201775CE00AF9E5A /* ImageView */, 53922DAC148C56DD0056699D /* Utils */, 53922DA9148C562D0056699D /* Categories */, 4369C2851D9811BB007E863A /* WebCache Categories */, @@ -2138,12 +2194,14 @@ 00733A721BC4880E00A5A117 /* UIView+WebCacheOperation.h in Headers */, 80377C481F2F666300F89830 /* bit_reader_utils.h in Headers */, 80377C511F2F666300F89830 /* huffman_encode_utils.h in Headers */, + 32484778201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 00733A6B1BC4880E00A5A117 /* NSData+ImageContentType.h in Headers */, 325312CB200F09910046BF1E /* SDWebImageTransition.h in Headers */, 323F8C111F38EF770092B609 /* muxi.h in Headers */, 80377EC41F2F66D500F89830 /* vp8li_dec.h in Headers */, 00733A6A1BC4880E00A5A117 /* SDWebImagePrefetcher.h in Headers */, 00733A641BC4880E00A5A117 /* SDWebImageOperation.h in Headers */, + 32484766201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 321E60A51F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, 32CF1C0A1FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, 80377C4D1F2F666300F89830 /* endian_inl_utils.h in Headers */, @@ -2154,6 +2212,7 @@ 80377EC21F2F66D500F89830 /* vp8i_dec.h in Headers */, 80377EBA1F2F66D500F89830 /* common_dec.h in Headers */, 43CE757E1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, + 3248476C201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 80377C5F1F2F666300F89830 /* utils.h in Headers */, 80377C5B1F2F666300F89830 /* rescaler_utils.h in Headers */, 323F8BF91F38EF770092B609 /* animi.h in Headers */, @@ -2205,9 +2264,11 @@ 4314D1701D0E0E3B004B36C9 /* mux.h in Headers */, 321E60871F38E8C800405457 /* SDWebImageCoder.h in Headers */, 80377EA21F2F66D400F89830 /* vp8i_dec.h in Headers */, + 3248476A201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 321E60951F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, 80377C211F2F666300F89830 /* quant_levels_dec_utils.h in Headers */, 4314D1721D0E0E3B004B36C9 /* SDWebImageCompat.h in Headers */, + 32484776201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 80377C251F2F666300F89830 /* random_utils.h in Headers */, 80377D4F1F2F66A700F89830 /* lossless.h in Headers */, 80377D511F2F66A700F89830 /* msa_macro.h in Headers */, @@ -2238,6 +2299,7 @@ 323F8B871F38EF770092B609 /* histogram_enc.h in Headers */, 80377C1F1F2F666300F89830 /* huffman_utils.h in Headers */, 4314D17F1D0E0E3B004B36C9 /* UIButton+WebCache.h in Headers */, + 32484764201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 4314D1811D0E0E3B004B36C9 /* UIImageView+WebCache.h in Headers */, 4314D1841D0E0E3B004B36C9 /* SDWebImageOperation.h in Headers */, 4314D1851D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.h in Headers */, @@ -2266,6 +2328,7 @@ 80377EC81F2F66D500F89830 /* alphai_dec.h in Headers */, 43A62A1B1D0E0A800089D7DD /* decode.h in Headers */, 321E608A1F38E8C800405457 /* SDWebImageCoder.h in Headers */, + 32484767201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80377C601F2F666400F89830 /* bit_reader_inl_utils.h in Headers */, 329A185D1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 431BB6DC1D06D2C1006A3455 /* UIButton+WebCache.h in Headers */, @@ -2328,9 +2391,11 @@ 321E60B41F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 32F7C0732030114C00873181 /* SDWebImageTransformer.h in Headers */, 431BB6FA1D06D2C1006A3455 /* SDWebImageDownloader.h in Headers */, + 3248476D201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 80377DF51F2F66A800F89830 /* common_sse2.h in Headers */, 323F8BDC1F38EF770092B609 /* vp8i_enc.h in Headers */, 80377ED21F2F66D500F89830 /* vp8i_dec.h in Headers */, + 32484779201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 43A918681D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2358,6 +2423,7 @@ 321E60991F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, 323F8B8B1F38EF770092B609 /* histogram_enc.h in Headers */, 4397D2C41D0DDD8C00BB2784 /* SDImageCache.h in Headers */, + 3248476E201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 4397D2C51D0DDD8C00BB2784 /* UIImageView+WebCache.h in Headers */, 3290FA091FA478AF0047D20C /* SDWebImageFrame.h in Headers */, 4369C27C1D9807EC007E863A /* UIView+WebCache.h in Headers */, @@ -2371,6 +2437,7 @@ 4397D2D11D0DDD8C00BB2784 /* decode.h in Headers */, 80377E481F2F66A800F89830 /* dsp.h in Headers */, 323F8BE91F38EF770092B609 /* vp8li_enc.h in Headers */, + 3248477A201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 329A185E1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 320224BB203979BA00E9F285 /* SDAnimatedImageRep.h in Headers */, 80377E761F2F66A800F89830 /* yuv.h in Headers */, @@ -2406,6 +2473,7 @@ 321E608B1F38E8C800405457 /* SDWebImageCoder.h in Headers */, 323F8B731F38EF770092B609 /* delta_palettization_enc.h in Headers */, 321E60C31F38E91700405457 /* UIImage+ForceDecode.h in Headers */, + 32484768201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80377E561F2F66A800F89830 /* lossless_common.h in Headers */, 4397D2E91D0DDD8C00BB2784 /* UIImage+WebP.h in Headers */, 325312CD200F09910046BF1E /* SDWebImageTransition.h in Headers */, @@ -2473,12 +2541,14 @@ 4A2CAE371AB4BB7500B6BC39 /* UIView+WebCacheOperation.h in Headers */, 80377C2E1F2F666300F89830 /* bit_reader_utils.h in Headers */, 80377C371F2F666300F89830 /* huffman_encode_utils.h in Headers */, + 32484777201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 4A2CAE2F1AB4BB7500B6BC39 /* UIImage+MultiFormat.h in Headers */, 325312CA200F09910046BF1E /* SDWebImageTransition.h in Headers */, 323F8C101F38EF770092B609 /* muxi.h in Headers */, 80377EB41F2F66D400F89830 /* vp8li_dec.h in Headers */, 4A2CAE1A1AB4BB6400B6BC39 /* SDWebImageOperation.h in Headers */, 80377C331F2F666300F89830 /* endian_inl_utils.h in Headers */, + 32484765201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 321E60A41F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, 32CF1C091FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, 4A2CAE1B1AB4BB6800B6BC39 /* SDWebImageDownloader.h in Headers */, @@ -2489,6 +2559,7 @@ 80377EAA1F2F66D400F89830 /* common_dec.h in Headers */, 80377C451F2F666300F89830 /* utils.h in Headers */, 80377C411F2F666300F89830 /* rescaler_utils.h in Headers */, + 3248476B201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 4A2CAE311AB4BB7500B6BC39 /* UIImage+WebP.h in Headers */, 323F8BF81F38EF770092B609 /* animi.h in Headers */, 80377C351F2F666300F89830 /* filters_utils.h in Headers */, @@ -2536,6 +2607,7 @@ 807A12281F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, 80377C051F2F665300F89830 /* huffman_utils.h in Headers */, 80377E881F2F66D000F89830 /* alphai_dec.h in Headers */, + 32484775201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 321E60941F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, 431738BD1CDFC2660008FEB9 /* decode.h in Headers */, 80377D0B1F2F66A100F89830 /* mips_macro.h in Headers */, @@ -2558,6 +2630,7 @@ 5376131F155AD0D5005750A4 /* UIButton+WebCache.h in Headers */, 53761320155AD0D5005750A4 /* UIImageView+WebCache.h in Headers */, 530E49E816464C25002868E7 /* SDWebImageOperation.h in Headers */, + 32484769201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 80377E961F2F66D000F89830 /* webpi_dec.h in Headers */, 80377BF81F2F665300F89830 /* bit_reader_inl_utils.h in Headers */, 530E49EA16464C7C002868E7 /* SDWebImageDownloaderOperation.h in Headers */, @@ -2575,6 +2648,7 @@ 321E60861F38E8C800405457 /* SDWebImageCoder.h in Headers */, 321E60B01F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 80377C0D1F2F665300F89830 /* rescaler_utils.h in Headers */, + 32484763201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80377E911F2F66D000F89830 /* vp8_dec.h in Headers */, 323F8B6E1F38EF770092B609 /* delta_palettization_enc.h in Headers */, 438096721CDFC08200DC626B /* MKAnnotationView+WebCache.h in Headers */, @@ -2885,6 +2959,7 @@ 80377EBF1F2F66D500F89830 /* tree_dec.c in Sources */, 80377DD21F2F66A700F89830 /* lossless_enc_sse41.c in Sources */, 80377DB31F2F66A700F89830 /* cost_sse2.c in Sources */, + 32484760201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 80377DDE1F2F66A700F89830 /* rescaler_mips32.c in Sources */, 80377DCA1F2F66A700F89830 /* filters_sse2.c in Sources */, 80377EBE1F2F66D500F89830 /* quant_dec.c in Sources */, @@ -2894,6 +2969,7 @@ 80377DC11F2F66A700F89830 /* enc_mips32.c in Sources */, 80377DBC1F2F66A700F89830 /* dec_sse41.c in Sources */, 80377DCE1F2F66A700F89830 /* lossless_enc_mips32.c in Sources */, + 3248477E201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, 80377DCB1F2F66A700F89830 /* filters.c in Sources */, 80377DAA1F2F66A700F89830 /* alpha_processing_sse2.c in Sources */, 43A9186E1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, @@ -2919,6 +2995,7 @@ 80377C561F2F666300F89830 /* quant_levels_utils.c in Sources */, 323F8BCF1F38EF770092B609 /* token_enc.c in Sources */, 80377DD11F2F66A700F89830 /* lossless_enc_sse2.c in Sources */, + 32484772201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 323F8C1D1F38EF770092B609 /* muxread.c in Sources */, 807A12311F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */, 80377C491F2F666300F89830 /* bit_writer_utils.c in Sources */, @@ -3052,8 +3129,11 @@ 323F8B7B1F38EF770092B609 /* frame_enc.c in Sources */, 80377D211F2F66A700F89830 /* alpha_processing_sse41.c in Sources */, 323F8B8D1F38EF770092B609 /* iterator_enc.c in Sources */, + 3248475E201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 80377D481F2F66A700F89830 /* lossless_enc_sse41.c in Sources */, + 32484770201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 323F8BA91F38EF770092B609 /* picture_psnr_enc.c in Sources */, + 3248477C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, 323F8C091F38EF770092B609 /* muxedit.c in Sources */, 80377D1F1F2F66A700F89830 /* alpha_processing_neon.c in Sources */, 32C0FDE82013426C001B8F2D /* SDWebImageIndicator.m in Sources */, @@ -3202,8 +3282,11 @@ 80377ECC1F2F66D500F89830 /* idec_dec.c in Sources */, 323F8B7E1F38EF770092B609 /* frame_enc.c in Sources */, 80377E171F2F66A800F89830 /* lossless_enc_sse41.c in Sources */, + 32484761201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 323F8B901F38EF770092B609 /* iterator_enc.c in Sources */, + 32484773201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 80377C611F2F666400F89830 /* bit_reader_utils.c in Sources */, + 3248477F201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, 323F8BAC1F38EF770092B609 /* picture_psnr_enc.c in Sources */, 323F8C0C1F38EF770092B609 /* muxedit.c in Sources */, 32C0FDEB2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, @@ -3308,6 +3391,7 @@ 80377E4C1F2F66A800F89830 /* enc_msa.c in Sources */, 80377E4E1F2F66A800F89830 /* enc_sse2.c in Sources */, 80377E6C1F2F66A800F89830 /* rescaler.c in Sources */, + 32484762201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 80377EE31F2F66D500F89830 /* vp8l_dec.c in Sources */, 80377ED71F2F66D500F89830 /* alpha_dec.c in Sources */, 323F8B7F1F38EF770092B609 /* frame_enc.c in Sources */, @@ -3385,6 +3469,7 @@ 323F8B5B1F38EF770092B609 /* config_enc.c in Sources */, 80377E361F2F66A800F89830 /* alpha_processing.c in Sources */, 80377E351F2F66A800F89830 /* alpha_processing_sse41.c in Sources */, + 32484780201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, 323F8B791F38EF770092B609 /* filter_enc.c in Sources */, 80377EDD1F2F66D500F89830 /* io_dec.c in Sources */, 43A918701D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, @@ -3402,6 +3487,7 @@ 321E60BB1F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 80377E3C1F2F66A800F89830 /* cost_mips32.c in Sources */, 80377E421F2F66A800F89830 /* dec_mips32.c in Sources */, + 32484774201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 4397D2AE1D0DDD8C00BB2784 /* UIImageView+HighlightedWebCache.m in Sources */, 323F8B851F38EF770092B609 /* histogram_enc.c in Sources */, 80377EE51F2F66D500F89830 /* webp_dec.c in Sources */, @@ -3492,6 +3578,7 @@ 80377EAF1F2F66D400F89830 /* tree_dec.c in Sources */, 4A2CAE281AB4BB7500B6BC39 /* MKAnnotationView+WebCache.m in Sources */, 4A2CAE261AB4BB7000B6BC39 /* SDWebImagePrefetcher.m in Sources */, + 3248475F201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 80377C441F2F666300F89830 /* utils.c in Sources */, 80377D8D1F2F66A700F89830 /* lossless_enc_sse41.c in Sources */, 80377EAE1F2F66D400F89830 /* quant_dec.c in Sources */, @@ -3501,6 +3588,7 @@ 80377D851F2F66A700F89830 /* filters_sse2.c in Sources */, 80377D711F2F66A700F89830 /* dec_clip_tables.c in Sources */, 43A9186D1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, + 3248477D201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, 80377D7C1F2F66A700F89830 /* enc_mips32.c in Sources */, 80377D771F2F66A700F89830 /* dec_sse41.c in Sources */, 80377D891F2F66A700F89830 /* lossless_enc_mips32.c in Sources */, @@ -3526,6 +3614,7 @@ 4A2CAE191AB4BB6400B6BC39 /* SDWebImageCompat.m in Sources */, 80377DA11F2F66A700F89830 /* upsampling_sse2.c in Sources */, 323F8BCE1F38EF770092B609 /* token_enc.c in Sources */, + 32484771201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 80377C3C1F2F666300F89830 /* quant_levels_utils.c in Sources */, 323F8C1C1F38EF770092B609 /* muxread.c in Sources */, 807A12301F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */, @@ -3646,6 +3735,7 @@ 5376130C155AD0D5005750A4 /* SDWebImageManager.m in Sources */, 5376130D155AD0D5005750A4 /* SDWebImagePrefetcher.m in Sources */, 80377C101F2F665300F89830 /* utils.c in Sources */, + 3248475D201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 80377D031F2F66A100F89830 /* lossless_enc_sse41.c in Sources */, 80377E8E1F2F66D000F89830 /* quant_dec.c in Sources */, 80377CE41F2F66A100F89830 /* cost_sse2.c in Sources */, @@ -3655,6 +3745,7 @@ 80377CE71F2F66A100F89830 /* dec_clip_tables.c in Sources */, 43A9186B1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, 80377CF21F2F66A100F89830 /* enc_mips32.c in Sources */, + 3248477B201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, 80377CED1F2F66A100F89830 /* dec_sse41.c in Sources */, 80377CFF1F2F66A100F89830 /* lossless_enc_mips32.c in Sources */, 80377CFC1F2F66A100F89830 /* filters.c in Sources */, @@ -3680,6 +3771,7 @@ 80377D171F2F66A100F89830 /* upsampling_sse2.c in Sources */, 323F8BCC1F38EF770092B609 /* token_enc.c in Sources */, 80377C081F2F665300F89830 /* quant_levels_utils.c in Sources */, + 3248476F201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 323F8C1A1F38EF770092B609 /* muxread.c in Sources */, 807A122E1F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */, 80377BFB1F2F665300F89830 /* bit_writer_utils.c in Sources */, diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h new file mode 100644 index 00000000..141d5462 --- /dev/null +++ b/SDWebImage/SDAnimatedImage.h @@ -0,0 +1,66 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import "NSData+ImageContentType.h" + +@protocol SDAnimatedImage + +@required +/** + Total animated frame count. + It the frame count is less than 1, then the methods below will be ignored. + + @return Total animated frame count. + */ +- (NSUInteger)animatedImageFrameCount; +/** + Animation loop count, 0 means infinite looping. + + @return Animation loop count + */ +- (NSUInteger)animatedImageLoopCount; +/** + Returns the frame image from a specified index. + This method may be called on background thread. And the index maybe randomly if one image was set to different imageViews, keep it re-entrant. + + @param index Frame index (zero based). + @return Frame's image + */ +- (nullable UIImage *)animatedImageFrameAtIndex:(NSUInteger)index; +/** + Returns the frames's duration from a specified index. + + @param index Frame index (zero based). + @return Frame's duration + */ +- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index; + +@end + +@interface SDAnimatedImage : UIImage + +// This class override these methods from UIImage(NSImage), and it supports NSSecureCoding. +// You should use these methods to create a new animated image. Use other methods will just call super instead. ++ (nullable instancetype)imageWithContentsOfFile:(nonnull NSString *)path; ++ (nullable instancetype)imageWithData:(nonnull NSData *)data; ++ (nullable instancetype)imageWithData:(nonnull NSData *)data scale:(CGFloat)scale; +- (nullable instancetype)initWithContentsOfFile:(nonnull NSString *)path; +- (nullable instancetype)initWithData:(nonnull NSData *)data; +- (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale; + +/** + 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 + */ +@property (nonatomic, copy, readonly, nullable) NSData *animatedImageData; + +@end diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m new file mode 100644 index 00000000..668b5a9a --- /dev/null +++ b/SDWebImage/SDAnimatedImage.m @@ -0,0 +1,167 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDAnimatedImage.h" +#import "NSImage+Additions.h" +#import "UIImage+WebCache.h" +#import "SDWebImageCoder.h" +#import "SDWebImageCodersManager.h" + +static CGFloat SDImageScaleFromPath(NSString *string) { + if (string.length == 0 || [string hasSuffix:@"/"]) return 1; + NSString *name = string.stringByDeletingPathExtension; + __block CGFloat scale = 1; + + NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines error:nil]; + [pattern enumerateMatchesInString:name options:kNilOptions range:NSMakeRange(0, name.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { + if (result.range.location >= 3) { + scale = [string substringWithRange:NSMakeRange(result.range.location + 1, result.range.length - 2)].doubleValue; + } + }]; + + return scale; +} + +@interface SDAnimatedImage () + +@property (nonatomic, strong) id coder; +@property (nonatomic, assign, readwrite) NSUInteger animatedImageLoopCount; +@property (nonatomic, assign, readwrite) NSUInteger animatedImageFrameCount; +@property (nonatomic, assign, readwrite) SDImageFormat animatedImageFormat; +@property (nonatomic, assign) BOOL animatedImageLoopCountCheck; +@property (nonatomic, assign) BOOL animatedImageFrameCountChecked; + +#if SD_MAC +@property (nonatomic, assign) CGFloat scale; +#endif + +@end + +@implementation SDAnimatedImage + +#pragma mark - UIImage override method ++ (instancetype)imageWithContentsOfFile:(NSString *)path { + return [[self alloc] initWithContentsOfFile:path]; +} + ++ (instancetype)imageWithData:(NSData *)data { + return [[self alloc] initWithData:data]; +} + ++ (instancetype)imageWithData:(NSData *)data scale:(CGFloat)scale { + return [[self alloc] initWithData:data scale:scale]; +} + +- (instancetype)initWithContentsOfFile:(NSString *)path { + NSData *data = [NSData dataWithContentsOfFile:path]; + return [self initWithData:data scale:SDImageScaleFromPath(path)]; +} + +- (instancetype)initWithData:(NSData *)data { + return [self initWithData:data scale:1]; +} + +- (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale { + if (!data || data.length == 0) { + return nil; + } + if (scale <= 0) { +#if SD_WATCH + scale = [WKInterfaceDevice currentDevice].screenScale; +#elif SD_UIKIT + scale = [UIScreen mainScreen].scale; +#endif + } + for (idcoder in [SDWebImageCodersManager sharedInstance].coders) { + if ([coder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { + if ([coder canDecodeFromData:data]) { + id animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data]; + if (!animatedCoder) { + // check next coder + continue; + } else { + self.coder = animatedCoder; + break; + } + } + } + } + if (!self.coder) { + return nil; + } + UIImage *image = [self.coder animatedImageFrameAtIndex:0]; + if (!image) { + return nil; + } +#if SD_MAC + self = [super initWithCGImage:image.CGImage size:NSZeroSize]; +#else + self = [super initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; +#endif + if (!self) { + return nil; + } + SDImageFormat format = [NSData sd_imageFormatForImageData:data]; + self.animatedImageFormat = format; + return self; +} + +#pragma mark - NSSecureCoding +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + NSNumber *scale = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(scale))]; + NSData *animatedImageData = [aDecoder decodeObjectOfClass:[NSData class] forKey:NSStringFromSelector(@selector(animatedImageData))]; + if (animatedImageData) { + return [self initWithData:animatedImageData scale:scale.doubleValue]; + } else { + return [super initWithCoder:aDecoder]; + } +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + if (self.animatedImageData) { + [aCoder encodeObject:self.animatedImageData forKey:NSStringFromSelector(@selector(animatedImageData))]; + [aCoder encodeObject:@(self.scale) forKey:NSStringFromSelector(@selector(scale))]; + } else { + [super encodeWithCoder:aCoder]; + } +} + ++ (BOOL)supportsSecureCoding { + return YES; +} + +#pragma mark - SDAnimatedImage +- (NSUInteger)animatedImageLoopCount { + if (!self.animatedImageLoopCountCheck) { + self.animatedImageLoopCountCheck = YES; + _animatedImageLoopCount = [self.coder animatedImageLoopCount]; + } + return _animatedImageLoopCount; +} + +- (NSUInteger)animatedImageFrameCount { + if (!self.animatedImageFrameCountChecked) { + self.animatedImageFrameCountChecked = YES; + _animatedImageFrameCount = [self.coder animatedImageFrameCount]; + } + return _animatedImageFrameCount; +} + +- (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { + return [self.coder animatedImageFrameAtIndex:index]; +} + +- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { + return [self.coder animatedImageDurationAtIndex:index]; +} + +- (NSData *)animatedImageData { + return self.coder.animatedImageData; +} + +@end diff --git a/SDWebImage/SDAnimatedImageView+WebCache.h b/SDWebImage/SDAnimatedImageView+WebCache.h new file mode 100644 index 00000000..ab528b70 --- /dev/null +++ b/SDWebImage/SDAnimatedImageView+WebCache.h @@ -0,0 +1,126 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDAnimatedImageView.h" + +#if SD_UIKIT || SD_MAC + +#import "SDWebImageManager.h" + +@interface SDAnimatedImageView (WebCache) + +/** + * Set the imageView `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `image` with an `url` and a placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @see sd_setImageWithURL:placeholderImage:options: + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url`, placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + +@end + +#endif diff --git a/SDWebImage/SDAnimatedImageView+WebCache.m b/SDWebImage/SDAnimatedImageView+WebCache.m new file mode 100644 index 00000000..a4a8c9db --- /dev/null +++ b/SDWebImage/SDAnimatedImageView+WebCache.m @@ -0,0 +1,57 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDAnimatedImageView+WebCache.h" + +#if SD_UIKIT || SD_MAC + +#import "UIView+WebCache.h" + +@implementation SDAnimatedImageView (WebCache) + +- (void)sd_setImageWithURL:(nullable NSURL *)url { + [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder { + [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_internalSetImageWithURL:url + placeholderImage:placeholder + options:options + operationKey:nil + setImageBlock:nil + progress:progressBlock + completed:completedBlock]; +} + +@end + +#endif diff --git a/SDWebImage/SDAnimatedImageView.h b/SDWebImage/SDAnimatedImageView.h new file mode 100644 index 00000000..b31d5806 --- /dev/null +++ b/SDWebImage/SDAnimatedImageView.h @@ -0,0 +1,59 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +#if SD_UIKIT || SD_MAC + +/** + A drop-in replacement for UIImageView/NSImageView, you can use this for animated image rendering. + Call `setImage:` with a `UIImage` will start animated image rendering. Call with a UIImage(NSImage) will back to normal UIImageView(NSImageView) rendering + For UIKit: use `-startAnimating`, `-stopAnimating` to control animating + For AppKit: use `-setAnimates:` to control animating. This view is layer-backed. + */ +@interface SDAnimatedImageView : UIImageView + +/** + Current display frame image + */ +@property (nonatomic, strong, readonly, nullable) UIImage *currentFrame; +/** + Current frame index, zero based + */ +@property (nonatomic, assign, readonly) NSUInteger currentFrameIndex; +/** + Current loop count since its latest animating + */ +@property (nonatomic, assign, readonly) NSUInteger currentLoopCount; +/** + YES to choose `animationRepeatCount` property instead of image's loop count for animtion loop count. Default is NO. + */ +@property (nonatomic, assign) BOOL shouldCustomLoopCount; +/** + Total loop count for animated image rendering. Default is animated image's loop count. + If you need to set custom loop count, set `shouldCustomLoopCount` to YES and change this value. + This class override UIImageView's `animationRepeatCount` property on iOS, use this property as well. + */ +@property (nonatomic, assign) NSInteger animationRepeatCount; +/** + Provide a max buffer size by bytes. This is used to adjust frame buffer count and can be useful when the decoding cost is expensive (such as Animated WebP software decoding). Default is 0. + `0` means automatically adjust by calculating current memory usage. + `1` means without any buffer cache, each of frames will be decoded and then be freed after rendering. (Lowest Memory and Highest CPU) + `NSUIntegerMax` means cache all the buffer. (Lowest CPU and Highest Memory) + */ +@property (nonatomic, assign) NSUInteger maxBufferSize; +/** + You can specify a runloop mode to let it rendering. + Default is NSRunLoopCommonModes on multi-core iOS device, NSDefaultRunLoopMode on single-core iOS device + This value has no use on macOS + */ +@property (nonatomic, copy, nonnull) NSString *runLoopMode; + +@end + +#endif diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m new file mode 100644 index 00000000..35f1b500 --- /dev/null +++ b/SDWebImage/SDAnimatedImageView.m @@ -0,0 +1,757 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDAnimatedImageView.h" +#import "UIImage+WebCache.h" +#import "NSImage+Additions.h" +#if SD_UIKIT || SD_MAC +#import "SDAnimatedImage.h" +#import + +#if SD_MAC +#import +static CVReturn renderCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext); +#endif + +static NSUInteger SDDeviceTotalMemory() { + return [[NSProcessInfo processInfo] physicalMemory]; +} + +static NSUInteger SDDeviceFreeMemory() { + mach_port_t host_port = mach_host_self(); + mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t); + vm_size_t page_size; + vm_statistics_data_t vm_stat; + kern_return_t kern; + + kern = host_page_size(host_port, &page_size); + if (kern != KERN_SUCCESS) return 0; + kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size); + if (kern != KERN_SUCCESS) return 0; + return vm_stat.free_count * page_size; +} + +#define LOCK(...) dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER); \ +__VA_ARGS__; \ +dispatch_semaphore_signal(self->_lock); + +@interface SDWeakProxy : NSProxy + +@property (nonatomic, weak, readonly) id target; + +- (instancetype)initWithTarget:(id)target; ++ (instancetype)proxyWithTarget:(id)target; + +@end + +@implementation SDWeakProxy + +- (instancetype)initWithTarget:(id)target { + _target = target; + return self; +} + ++ (instancetype)proxyWithTarget:(id)target { + return [[SDWeakProxy alloc] initWithTarget:target]; +} + +- (id)forwardingTargetForSelector:(SEL)selector { + return _target; +} + +- (void)forwardInvocation:(NSInvocation *)invocation { + void *null = NULL; + [invocation setReturnValue:&null]; +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { + return [NSObject instanceMethodSignatureForSelector:@selector(init)]; +} + +- (BOOL)respondsToSelector:(SEL)aSelector { + return [_target respondsToSelector:aSelector]; +} + +- (BOOL)isEqual:(id)object { + return [_target isEqual:object]; +} + +- (NSUInteger)hash { + return [_target hash]; +} + +- (Class)superclass { + return [_target superclass]; +} + +- (Class)class { + return [_target class]; +} + +- (BOOL)isKindOfClass:(Class)aClass { + return [_target isKindOfClass:aClass]; +} + +- (BOOL)isMemberOfClass:(Class)aClass { + return [_target isMemberOfClass:aClass]; +} + +- (BOOL)conformsToProtocol:(Protocol *)aProtocol { + return [_target conformsToProtocol:aProtocol]; +} + +- (BOOL)isProxy { + return YES; +} + +- (NSString *)description { + return [_target description]; +} + +- (NSString *)debugDescription { + return [_target debugDescription]; +} + +@end + +@interface SDAnimatedImageView () + +@property (nonatomic, strong, readwrite) UIImage *currentFrame; +@property (nonatomic, assign, readwrite) NSUInteger currentFrameIndex; +@property (nonatomic, assign, readwrite) NSUInteger currentLoopCount; +@property (nonatomic, assign) NSUInteger totalFrameCount; +@property (nonatomic, assign) NSUInteger totalLoopCount; +@property (nonatomic, strong) UIImage *animatedImage; +@property (nonatomic, strong) NSMutableDictionary *frameBuffer; +@property (nonatomic, assign) NSTimeInterval currentTime; +@property (nonatomic, assign) BOOL bufferMiss; +@property (nonatomic, assign) BOOL shouldAnimate; +@property (nonatomic, assign) NSUInteger maxBufferCount; +@property (nonatomic, strong) NSOperationQueue *fetchQueue; +@property (nonatomic, strong) dispatch_semaphore_t lock; +#if SD_MAC +@property (nonatomic, assign) CVDisplayLinkRef displayLink; +#else +@property (nonatomic, strong) CADisplayLink *displayLink; +#endif + +@end + +@implementation SDAnimatedImageView +#if SD_UIKIT +@dynamic animationRepeatCount; +#endif + +#pragma mark - Initializers + +#if SD_MAC ++ (instancetype)imageViewWithImage:(NSImage *)image +{ + NSRect frame = NSMakeRect(0, 0, image.size.width, image.size.height); + SDAnimatedImageView *imageView = [[SDAnimatedImageView alloc] initWithFrame:frame]; + [imageView setImage:image]; + return imageView; +} +#else +// -initWithImage: isn't documented as a designated initializer of UIImageView, but it actually seems to be. +// Using -initWithImage: doesn't call any of the other designated initializers. +- (instancetype)initWithImage:(UIImage *)image +{ + self = [super initWithImage:image]; + if (self) { + [self commonInit]; + } + return self; +} + +// -initWithImage:highlightedImage: also isn't documented as a designated initializer of UIImageView, but it doesn't call any other designated initializers. +- (instancetype)initWithImage:(UIImage *)image highlightedImage:(UIImage *)highlightedImage +{ + self = [super initWithImage:image highlightedImage:highlightedImage]; + if (self) { + [self commonInit]; + } + return self; +} +#endif + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + [self commonInit]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder +{ + self = [super initWithCoder:aDecoder]; + if (self) { + [self commonInit]; + } + return self; +} + +- (void)commonInit +{ +#if SD_MAC + self.wantsLayer = YES; + self.imageScaling = NSImageScaleProportionallyDown; +#endif + self.maxBufferCount = 0; + self.runLoopMode = [[self class] defaultRunLoopMode]; + self.lock = dispatch_semaphore_create(1); +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif +} + + +- (void)resetAnimated +{ + LOCK({ + self.animatedImage = nil; + self.totalFrameCount = 0; + self.totalLoopCount = 0; + self.currentFrame = 0; + self.currentFrameIndex = 0; + self.currentLoopCount = 0; + self.currentTime = 0; + self.bufferMiss = NO; + self.shouldAnimate = NO; + self.maxBufferCount = 0; + [_frameBuffer removeAllObjects]; + _frameBuffer = nil; + [_fetchQueue cancelAllOperations]; + _fetchQueue = nil; + }); +} + +#pragma mark - Accessors +#pragma mark Public + +- (void)setImage:(UIImage *)image +{ + if (self.image == image) { + return; + } + [self stopAnimating]; + // Reset all value + [self resetAnimated]; + + super.image = image; + if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { + NSUInteger animatedImageFrameCount = ((UIImage *)image).animatedImageFrameCount; + if (animatedImageFrameCount <= 1) { + return; + } + self.animatedImage = (UIImage *)image; + self.totalFrameCount = animatedImageFrameCount; + self.totalLoopCount = self.animatedImage.animatedImageLoopCount; + // Ensure disabled highlighting; it's not supported (see `-setHighlighted:`). + super.highlighted = NO; + // UIImageView seems to bypass some accessors when calculating its intrinsic content size, so this ensures its intrinsic content size comes from the animated image. + [self invalidateIntrinsicContentSize]; + // Get the first frame + self.currentFrame = [self.animatedImage animatedImageFrameAtIndex:0]; + LOCK({ + if (self.currentFrame) { + self.frameBuffer[@(0)] = self.currentFrame; + self.bufferMiss = NO; + } else { + self.bufferMiss = YES; + } + }); + // Calculate max buffer size + [self calculateMaxBufferCount]; + // Update should animate + [self updateShouldAnimate]; + if (self.shouldAnimate) { + [self startAnimating]; + } + + [self.layer setNeedsDisplay]; + } +} + +- (void)setAnimationRepeatCount:(NSInteger)animationRepeatCount +{ +#if SD_MAC + _animationRepeatCount = animationRepeatCount; +#else + [super setAnimationRepeatCount:animationRepeatCount]; +#endif +} + +- (void)setRunLoopMode:(NSString *)runLoopMode +{ + if (![@[NSDefaultRunLoopMode, NSRunLoopCommonModes] containsObject:runLoopMode]) { + NSAssert(NO, @"Invalid run loop mode: %@", runLoopMode); + _runLoopMode = [[self class] defaultRunLoopMode]; + } else { + _runLoopMode = runLoopMode; + } +} + +#pragma mark - Private +- (NSOperationQueue *)fetchQueue +{ + if (!_fetchQueue) { + _fetchQueue = [[NSOperationQueue alloc] init]; + _fetchQueue.maxConcurrentOperationCount = 1; + } + return _fetchQueue; +} + +- (NSMutableDictionary *)frameBuffer +{ + if (!_frameBuffer) { + _frameBuffer = [NSMutableDictionary dictionary]; + } + return _frameBuffer; +} + +#if SD_MAC +- (CVDisplayLinkRef)displayLink +{ + if (!_displayLink) { + CGDirectDisplayID displayID = CGMainDisplayID(); + CVReturn error = CVDisplayLinkCreateWithCGDisplay(displayID, &_displayLink); + if (error) { + return NULL; + } + CVDisplayLinkSetOutputCallback(_displayLink, renderCallback, (__bridge void *)self); + } + return _displayLink; +} +#else +- (CADisplayLink *)displayLink +{ + if (!_displayLink) { + // It is important to note the use of a weak proxy here to avoid a retain cycle. `-displayLinkWithTarget:selector:` + // will retain its target until it is invalidated. We use a weak proxy so that the image view will get deallocated + // independent of the display link's lifetime. Upon image view deallocation, we invalidate the display + // link which will lead to the deallocation of both the display link and the weak proxy. + SDWeakProxy *weakProxy = [SDWeakProxy proxyWithTarget:self]; + _displayLink = [CADisplayLink displayLinkWithTarget:weakProxy selector:@selector(displayDidRefresh:)]; + [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:self.runLoopMode]; + } + return _displayLink; +} +#endif + +#pragma mark - Life Cycle + +- (void)dealloc +{ + // Removes the display link from all run loop modes. +#if SD_MAC + if (_displayLink) { + CVDisplayLinkRelease(_displayLink); + _displayLink = NULL; + } +#else + [_displayLink invalidate]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif +} + +- (void)didReceiveMemoryWarning:(NSNotification *)notification { + [_fetchQueue cancelAllOperations]; + [_fetchQueue addOperationWithBlock:^{ + NSNumber *currentFrameIndex = @(self.currentFrameIndex); + LOCK({ + NSArray *keys = self.frameBuffer.allKeys; + // only keep the next frame for later rendering + for (NSNumber * key in keys) { + if (![key isEqualToNumber:currentFrameIndex]) { + [self.frameBuffer removeObjectForKey:key]; + } + } + }); + }]; +} + +#pragma mark - UIView Method Overrides +#pragma mark Observing View-Related Changes + +#if SD_MAC +- (void)viewDidMoveToSuperview +#else +- (void)didMoveToSuperview +#endif +{ +#if SD_MAC + [super viewDidMoveToSuperview]; +#else + [super didMoveToSuperview]; +#endif + + [self updateShouldAnimate]; + if (self.shouldAnimate) { + [self startAnimating]; + } else { + [self stopAnimating]; + } +} + +#if SD_MAC +- (void)viewDidMoveToWindow +#else +- (void)didMoveToWindow +#endif +{ +#if SD_MAC + [super viewDidMoveToWindow]; +#else + [super didMoveToWindow]; +#endif + + [self updateShouldAnimate]; + if (self.shouldAnimate) { + [self startAnimating]; + } else { + [self stopAnimating]; + } +} + +#if SD_MAC +- (void)setAlphaValue:(CGFloat)alphaValue +#else +- (void)setAlpha:(CGFloat)alpha +#endif +{ +#if SD_MAC + [super setAlphaValue:alphaValue]; +#else + [super setAlpha:alpha]; +#endif + + [self updateShouldAnimate]; + if (self.shouldAnimate) { + [self startAnimating]; + } else { + [self stopAnimating]; + } +} + +- (void)setHidden:(BOOL)hidden +{ + [super setHidden:hidden]; + + [self updateShouldAnimate]; + if (self.shouldAnimate) { + [self startAnimating]; + } else { + [self stopAnimating]; + } +} + +#pragma mark Auto Layout + +- (CGSize)intrinsicContentSize +{ + // Default to let UIImageView handle the sizing of its image, and anything else it might consider. + CGSize intrinsicContentSize = [super intrinsicContentSize]; + + // If we have have an animated image, use its image size. + // UIImageView's intrinsic content size seems to be the size of its image. The obvious approach, simply calling `-invalidateIntrinsicContentSize` when setting an animated image, results in UIImageView steadfastly returning `{UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric}` for its intrinsicContentSize. + // (Perhaps UIImageView bypasses its `-image` getter in its implementation of `-intrinsicContentSize`, as `-image` is not called after calling `-invalidateIntrinsicContentSize`.) + if (self.animatedImage) { + intrinsicContentSize = self.image.size; + } + + return intrinsicContentSize; +} + +#if SD_MAC +#pragma mark - NSImageView Method Overrides +- (void)setImageScaling:(NSImageScaling)imageScaling { + [super setImageScaling:imageScaling]; + [self updateLayerContentsPlacement]; +} + +- (void)setImageAlignment:(NSImageAlignment)imageAlignment { + [super setImageAlignment:imageAlignment]; + [self updateLayerContentsPlacement]; +} + +- (void)updateLayerContentsPlacement { + NSImageScaling scale = self.imageScaling; + NSViewLayerContentsPlacement contentsPlacement = NSViewLayerContentsPlacementScaleAxesIndependently; + switch (scale) { + case NSImageScaleProportionallyDown: + contentsPlacement = NSViewLayerContentsPlacementScaleProportionallyToFit; break; + case NSImageScaleAxesIndependently: + contentsPlacement = NSViewLayerContentsPlacementScaleAxesIndependently; break; + case NSImageScaleProportionallyUpOrDown: + contentsPlacement = NSViewLayerContentsPlacementScaleProportionallyToFill; break; + case NSImageScaleNone: { + NSImageAlignment alignment = self.imageAlignment; + switch (alignment) { + case NSImageAlignCenter: + contentsPlacement = NSViewLayerContentsPlacementCenter; break; + case NSImageAlignTop: + contentsPlacement = NSViewLayerContentsPlacementTop; break; + case NSImageAlignTopLeft: + contentsPlacement = NSViewLayerContentsPlacementTopLeft; break; + case NSImageAlignTopRight: + contentsPlacement = NSViewLayerContentsPlacementTopRight; break; + case NSImageAlignLeft: + contentsPlacement = NSViewLayerContentsPlacementLeft; break; + case NSImageAlignBottom: + contentsPlacement = NSViewLayerContentsPlacementBottom; break; + case NSImageAlignBottomLeft: + contentsPlacement = NSViewLayerContentsPlacementBottomLeft; break; + case NSImageAlignBottomRight: + contentsPlacement = NSViewLayerContentsPlacementBottomRight; break; + case NSImageAlignRight: + contentsPlacement = NSViewLayerContentsPlacementRight; break; + } + break; + } + } + self.layerContentsPlacement = contentsPlacement; +} +#endif + + +#pragma mark - UIImageView Method Overrides +#pragma mark Image Data + +- (void)startAnimating +{ + if (self.animatedImage) { +#if SD_MAC + CVDisplayLinkStart(self.displayLink); +#else + self.displayLink.paused = NO; +#endif + } else { +#if SD_UIKIT + [super startAnimating]; +#endif + } +} + +- (void)stopAnimating +{ + if (self.animatedImage) { +#if SD_MAC + CVDisplayLinkStop(self.displayLink); +#else + self.displayLink.paused = YES; +#endif + } else { +#if SD_UIKIT + [super stopAnimating]; +#endif + } +} + +- (BOOL)isAnimating +{ + BOOL isAnimating = NO; + if (self.animatedImage) { +#if SD_MAC + isAnimating = CVDisplayLinkIsRunning(self.displayLink); +#else + isAnimating = !self.displayLink.isPaused; +#endif + } else { +#if SD_UIKIT + isAnimating = [super isAnimating]; +#endif + } + return isAnimating; +} + +#if SD_MAC +- (void)setAnimates:(BOOL)animates +{ + [super setAnimates:animates]; + if (animates) { + [self startAnimating]; + } else { + [self stopAnimating]; + } +} +#endif + +#pragma mark Highlighted Image Unsupport + +- (void)setHighlighted:(BOOL)highlighted +{ + // Highlighted image is unsupported for animated images, but implementing it breaks the image view when embedded in a UICollectionViewCell. + if (!self.animatedImage) { + [super setHighlighted:highlighted]; + } +} + + +#pragma mark - Private Methods +#pragma mark Animation + +// Don't repeatedly check our window & superview in `-displayDidRefresh:` for performance reasons. +// Just update our cached value whenever the animated image or visibility (window, superview, hidden, alpha) is changed. +- (void)updateShouldAnimate +{ +#if SD_MAC + BOOL isVisible = self.window && self.superview && ![self isHidden] && self.alphaValue > 0.0 && self.animates; +#else + BOOL isVisible = self.window && self.superview && ![self isHidden] && self.alpha > 0.0; +#endif + self.shouldAnimate = self.animatedImage && self.totalFrameCount > 1 && isVisible; +} + +#if SD_MAC +- (void)displayDidRefresh:(CVDisplayLinkRef)displayLink duration:(NSTimeInterval)duration +#else +- (void)displayDidRefresh:(CADisplayLink *)displayLink +#endif +{ + // If for some reason a wild call makes it through when we shouldn't be animating, bail. + // Early return! + if (!self.shouldAnimate) { + return; + } + +#if SD_UIKIT + NSTimeInterval duration = displayLink.duration * displayLink.frameInterval; +#endif + NSUInteger currentFrameIndex = self.currentFrameIndex; + NSUInteger nextFrameIndex = (currentFrameIndex + 1) % self.totalFrameCount; + + // Check if we have the frame buffer firstly to improve performance + if (!self.bufferMiss) { + // Then check if timestamp is reached + self.currentTime += duration; + NSTimeInterval currentDuration = [self.animatedImage animatedImageDurationAtIndex:currentFrameIndex]; + if (self.currentTime < currentDuration) { + // Current frame timestamp not reached, return + return; + } + self.currentTime -= currentDuration; + NSTimeInterval nextDuration = [self.animatedImage animatedImageDurationAtIndex:nextFrameIndex]; + if (self.currentTime > nextDuration) { + // Do not skip frame + self.currentTime = nextDuration; + } + } + + // Update the current frame + UIImage *currentFrame; + LOCK({ + currentFrame = self.frameBuffer[@(currentFrameIndex)]; + }); + if (currentFrame) { + LOCK({ + // Remove the frame buffer if need + if (self.frameBuffer.count > self.maxBufferCount) { + self.frameBuffer[@(currentFrameIndex)] = nil; + } + }); + self.currentFrame = currentFrame; + self.currentFrameIndex = nextFrameIndex; + self.bufferMiss = NO; + [self.layer setNeedsDisplay]; + } else { + self.bufferMiss = YES; + } + + // Update the loop count + if (nextFrameIndex == 0) { + self.currentLoopCount++; + // if reached the max loop count, stop animating, 0 means loop indefinitely + NSUInteger maxLoopCount = self.shouldCustomLoopCount ? self.animationRepeatCount : self.totalLoopCount; + if (maxLoopCount != 0 && (self.currentLoopCount >= maxLoopCount)) { + [self stopAnimating]; + return; + } + } + + // Check if we should prefetch next frame + if (self.fetchQueue.operationCount == 0 && self.frameBuffer.count < self.totalFrameCount) { + // Prefetch next frame in background queue + NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ + UIImage *nextFrame = [self.animatedImage animatedImageFrameAtIndex:nextFrameIndex]; + LOCK({ + self.frameBuffer[@(nextFrameIndex)] = nextFrame; + }); + }]; + [self.fetchQueue addOperation:operation]; + } +} + ++ (NSString *)defaultRunLoopMode +{ + // Key off `activeProcessorCount` (as opposed to `processorCount`) since the system could shut down cores in certain situations. + return [NSProcessInfo processInfo].activeProcessorCount > 1 ? NSRunLoopCommonModes : NSDefaultRunLoopMode; +} + + +#pragma mark - CALayerDelegate (Informal) +#pragma mark Providing the Layer's Content + +- (void)displayLayer:(CALayer *)layer +{ + if (_currentFrame) { + layer.contents = (__bridge id)_currentFrame.CGImage; + } +} + +#if SD_MAC +- (BOOL)wantsUpdateLayer +{ + return YES; +} + +- (void)updateLayer +{ + if (_currentFrame) { + self.layer.contents = (__bridge id)_currentFrame.CGImage; + } +} +#endif + + +#pragma mark - Util +- (void)calculateMaxBufferCount { + NSUInteger bytes = CGImageGetBytesPerRow(self.currentFrame.CGImage) * CGImageGetHeight(self.currentFrame.CGImage); + if (bytes == 0) bytes = 1024; + + NSUInteger max = 0; + if (self.maxBufferSize > 0) { + max = self.maxBufferSize; + } else { + // calculate based on current memory, these factors are by experience + NSUInteger total = SDDeviceTotalMemory(); + NSUInteger free = SDDeviceFreeMemory(); + max = MIN(total * 0.2, free * 0.6); + } + + NSUInteger maxBufferCount = (double)max / (double)bytes; + self.maxBufferCount = maxBufferCount; +} + +@end + +#if SD_MAC +static CVReturn renderCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) { + // Calculate refresh duration + NSTimeInterval duration = (double)inOutputTime->videoRefreshPeriod / ((double)inOutputTime->videoTimeScale * inOutputTime->rateScalar); + // CVDisplayLink callback is not on main queue + dispatch_async(dispatch_get_main_queue(), ^{ + [(__bridge SDAnimatedImageView *)displayLinkContext displayDidRefresh:displayLink duration:duration]; + }); + return kCVReturnSuccess; +} +#endif + +#endif diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index d790aef8..6d7c15a5 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -11,6 +11,7 @@ #import "NSImage+Additions.h" #import "SDWebImageCodersManager.h" #import "SDWebImageTransformer.h" +#import "SDWebImageCoderHelper.h" #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); #define UNLOCK(lock) dispatch_semaphore_signal(lock); @@ -294,12 +295,12 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (!data && image) { // If we do not have any data to detect image format, check whether it contains alpha channel to use PNG or JPEG format SDImageFormat format; - if (SDCGImageRefContainsAlpha(image.CGImage)) { + if ([SDWebImageCoderHelper imageRefContainsAlpha:image.CGImage]) { format = SDImageFormatPNG; } else { format = SDImageFormatJPEG; } - data = [[SDWebImageCodersManager sharedManager] encodedDataWithImage:image format:format]; + data = [[SDWebImageCodersManager sharedManager] encodedDataWithImage:image format:format options:nil]; } [self _storeImageDataToDisk:data forKey:key error:&writeError]; } @@ -476,10 +477,10 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { - (nullable UIImage *)diskImageForKey:(nullable NSString *)key data:(nullable NSData *)data { if (data) { - UIImage *image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:data]; + UIImage *image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:nil]; image = [self scaledImageForKey:key image:image]; if (self.config.shouldDecompressImages) { - image = [[SDWebImageCodersManager sharedManager] decompressedImageWithImage:image data:&data options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}]; + image = [SDWebImageCoderHelper decodedImageWithImage:image]; } return image; } else { diff --git a/SDWebImage/SDWebImageCoder.h b/SDWebImage/SDWebImageCoder.h index 7c0a63f2..2345df63 100644 --- a/SDWebImage/SDWebImageCoder.h +++ b/SDWebImage/SDWebImageCoder.h @@ -9,27 +9,19 @@ #import #import "SDWebImageCompat.h" #import "NSData+ImageContentType.h" +#import "SDAnimatedImage.h" + +typedef NSString * SDWebImageCoderOption NS_STRING_ENUM; +typedef NSDictionary SDWebImageCoderOptions; /** - A Boolean value indicating whether to scale down large images during decompressing. (NSNumber) + A Boolean value indicating whether to decode the first frame only for animated image during decoding. (NSNumber) */ -FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageCoderScaleDownLargeImagesKey; - +FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderDecodeFirstFrameOnly; /** - Return the shared device-dependent RGB color space created with CGColorSpaceCreateDeviceRGB. - - @return The device-dependent RGB color space + A double value between 0.0-1.0 indicating the encode quality to produce the image data. If not provide, use 1.0. (NSNumber) */ -CG_EXTERN CGColorSpaceRef _Nonnull SDCGColorSpaceGetDeviceRGB(void); - -/** - Check whether CGImageRef contains alpha channel. - - @param imageRef The CGImageRef - @return Return YES if CGImageRef contains alpha channel, otherwise return NO - */ -CG_EXTERN BOOL SDCGImageRefContainsAlpha(_Nullable CGImageRef imageRef); - +FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeQuality; /** This is the image coder protocol to provide custom image decoding/encoding. @@ -52,21 +44,11 @@ CG_EXTERN BOOL SDCGImageRefContainsAlpha(_Nullable CGImageRef imageRef); Decode the image data to image. @param data The image data to be decoded + @param optionsDict A dictionary containing any decoding options. Pass {SDWebImageCoderDecodeFirstFrameOnlyKey: @(YES)} to decode the first frame only. @return The decoded image from data */ -- (nullable UIImage *)decodedImageWithData:(nullable NSData *)data; - -/** - Decompress the image with original image and image data. - - @param image The original image to be decompressed - @param data The pointer to original image data. The pointer itself is nonnull but image data can be null. This data will set to cache if needed. If you do not need to modify data at the sametime, ignore this param. - @param optionsDict A dictionary containing any decompressing options. Pass {SDWebImageCoderScaleDownLargeImagesKey: @(YES)} to scale down large images - @return The decompressed image - */ -- (nullable UIImage *)decompressedImageWithImage:(nullable UIImage *)image - data:(NSData * _Nullable * _Nonnull)data - options:(nullable NSDictionary*)optionsDict; +- (nullable UIImage *)decodedImageWithData:(nullable NSData *)data + options:(nullable SDWebImageCoderOptions *)options; #pragma mark - Encoding @@ -85,7 +67,9 @@ CG_EXTERN BOOL SDCGImageRefContainsAlpha(_Nullable CGImageRef imageRef); @param format The image format to encode, you should note `SDImageFormatUndefined` format is also possible @return The encoded image data */ -- (nullable NSData *)encodedDataWithImage:(nullable UIImage *)image format:(SDImageFormat)format; +- (nullable NSData *)encodedDataWithImage:(nullable UIImage *)image + format:(SDImageFormat)format + options:(nullable SDWebImageCoderOptions *)options; @end @@ -106,14 +90,43 @@ CG_EXTERN BOOL SDCGImageRefContainsAlpha(_Nullable CGImageRef imageRef); */ - (BOOL)canIncrementallyDecodeFromData:(nullable NSData *)data; +/** + Because incremental decoding need to keep the decoded context, we will alloc a new instance with the same class for each download operation to avoid conflicts + This init method should not return nil + + @return A new instance to do incremental decoding for the specify image format + */ +- (nonnull instancetype)initIncrementally; + /** Incremental decode the image data to image. @param data The image data has been downloaded so far @param finished Whether the download has finished - @warning because incremental decoding need to keep the decoded context, we will alloc a new instance with the same class for each download operation to avoid conflicts @return The decoded image from data */ - (nullable UIImage *)incrementallyDecodedImageWithData:(nullable NSData *)data finished:(BOOL)finished; @end + +@protocol SDWebImageAnimatedCoder + +@required +/** + Because animated image coder should keep the original data, we will alloc a new instance with the same class for the specify animated image data + The init method should return nil if it can't decode the specify animated image data + + @param data The animated image data to be decode + @return A new instance to do animated decoding for specify image data + */ +- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data; + +/** + Return the current animated image data. This is used for image instance archive or image information retrieval + You can return back the desired data(may be not the same instance provide for init method, but have the equal data) + + @return The animated image data + */ +- (nullable NSData *)animatedImageData; + +@end diff --git a/SDWebImage/SDWebImageCoder.m b/SDWebImage/SDWebImageCoder.m index 9357fe52..4f66a48c 100644 --- a/SDWebImage/SDWebImageCoder.m +++ b/SDWebImage/SDWebImageCoder.m @@ -8,24 +8,5 @@ #import "SDWebImageCoder.h" -NSString * const SDWebImageCoderScaleDownLargeImagesKey = @"scaleDownLargeImages"; - -CGColorSpaceRef SDCGColorSpaceGetDeviceRGB(void) { - static CGColorSpaceRef colorSpace; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - colorSpace = CGColorSpaceCreateDeviceRGB(); - }); - return colorSpace; -} - -BOOL SDCGImageRefContainsAlpha(CGImageRef imageRef) { - if (!imageRef) { - return NO; - } - CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef); - BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone || - alphaInfo == kCGImageAlphaNoneSkipFirst || - alphaInfo == kCGImageAlphaNoneSkipLast); - return hasAlpha; -} +SDWebImageCoderOption const SDWebImageCoderDecodeFirstFrameOnly = @"decodeFirstFrameOnly"; +SDWebImageCoderOption const SDWebImageCoderEncodeQuality = @"encodeQuality"; diff --git a/SDWebImage/SDWebImageCoderHelper.h b/SDWebImage/SDWebImageCoderHelper.h index ad2fe855..4a4cbd31 100644 --- a/SDWebImage/SDWebImageCoderHelper.h +++ b/SDWebImage/SDWebImageCoderHelper.h @@ -30,7 +30,58 @@ @param animatedImage A animated image. If it's not animated, return nil @return The frames array */ -+ (NSArray * _Nullable)framesFromAnimatedImage:(UIImage * _Nullable)animatedImage; ++ (NSArray * _Nullable)framesFromAnimatedImage:(UIImage * _Nullable)animatedImage NS_SWIFT_NAME(frames(from:)); + +/** + Return the shared device-dependent RGB color space. + On iOS, it's created with deviceRGB (if available, use sRGB). + On macOS, it's from the screen colorspace (if failed, use deviceRGB) + Because it's shared, you should not retain or release this object. + + @return The device-dependent RGB color space + */ ++ (CGColorSpaceRef _Nonnull)colorSpaceGetDeviceRGB CF_RETURNS_NOT_RETAINED; + +/** + Retuen the color space of the CGImage + + @param imageRef The CGImage + @return The color space of CGImage, or if not supported, return the device-dependent RGB color space + */ ++ (CGColorSpaceRef _Nonnull)imageRefGetColorSpace:(_Nonnull CGImageRef)imageRef CF_RETURNS_NOT_RETAINED; + +/** + Check whether CGImage contains alpha channel. + + @param imageRef The CGImage + @return Return YES if CGImage contains alpha channel, otherwise return NO + */ ++ (BOOL)imageRefContainsAlpha:(_Nonnull CGImageRef)imageRef; + +/** + Create a decoded image by the provided image. This follows The Create Rule and you are response to call release after usage. + It will detect whether image contains alpha channel, then create a new bitmap context with the same size of image, and draw it. This can ensure that the image do not need extra decoding after been set to the imageView. + + @param imageRef The CGImage + @return A new created decoded image + */ ++ (CGImageRef _Nullable)imageRefCreateDecoded:(_Nonnull CGImageRef)imageRef CF_RETURNS_RETAINED; + +/** + Return the decoded image by the provided image. This one unlike `imageRefCreateDecoded:`, will not decode the image which contains alpha channel or animated image + @param image The image to be decoded + @return The decoded image + */ ++ (UIImage * _Nullable)decodedImageWithImage:(UIImage * _Nullable)image; + +/** + Return the decoded and probably scaled down image by the provided image. If the image is large than the limit size, will try to scale down. Or just works as `decodedImageWithImage:` + + @param image The image to be decoded and scaled down + @param bytes The limit bytes size. Provide 0 to use the build-in limit. + @return The decoded and probably scaled down image + */ ++ (UIImage * _Nullable)decodedAndScaledDownImageWithImage:(UIImage * _Nullable)image limitBytes:(NSUInteger)bytes; #if SD_UIKIT || SD_WATCH /** @@ -39,7 +90,8 @@ @param exifOrientation EXIF orientation @return iOS orientation */ -+ (UIImageOrientation)imageOrientationFromEXIFOrientation:(NSInteger)exifOrientation; ++ (UIImageOrientation)imageOrientationFromEXIFOrientation:(NSInteger)exifOrientation NS_SWIFT_NAME(imageOrientation(from:)); + /** Convert an iOS orientation to an EXIF image orientation. diff --git a/SDWebImage/SDWebImageCoderHelper.m b/SDWebImage/SDWebImageCoderHelper.m index 589b2900..71620cc2 100644 --- a/SDWebImage/SDWebImageCoderHelper.m +++ b/SDWebImage/SDWebImageCoderHelper.m @@ -13,6 +13,34 @@ #import #import "SDAnimatedImageRep.h" +#if SD_UIKIT || SD_WATCH +static const size_t kBytesPerPixel = 4; +static const size_t kBitsPerComponent = 8; + +/* + * Defines the maximum size in MB of the decoded image when the flag `SDWebImageScaleDownLargeImages` is set + * Suggested value for iPad1 and iPhone 3GS: 60. + * Suggested value for iPad2 and iPhone 4: 120. + * Suggested value for iPhone 3G and iPod 2 and earlier devices: 30. + */ +static const CGFloat kDestImageSizeMB = 120.f; + +/* + * Defines the maximum size in MB of a tile used to decode image when the flag `SDWebImageScaleDownLargeImages` is set + * Suggested value for iPad1 and iPhone 3GS: 20. + * Suggested value for iPad2 and iPhone 4: 40. + * Suggested value for iPhone 3G and iPod 2 and earlier devices: 10. + */ +static const CGFloat kSourceImageTileSizeMB = 40.f; + +static const CGFloat kBytesPerMB = 1024.0f * 1024.0f; +static const CGFloat kPixelsPerMB = kBytesPerMB / kBytesPerPixel; +static const CGFloat kDestTotalPixels = kDestImageSizeMB * kPixelsPerMB; +static const CGFloat kTileTotalPixels = kSourceImageTileSizeMB * kPixelsPerMB; + +static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to overlap the seems where tiles meet. +#endif + @implementation SDWebImageCoderHelper + (UIImage *)animatedImageWithFrames:(NSArray *)frames { @@ -149,7 +177,7 @@ // NSBitmapImageRep need to manually change frame. "Good taste" API [bitmapRep setProperty:NSImageCurrentFrame withValue:@(i)]; float frameDuration = [[bitmapRep valueForProperty:NSImageCurrentFrameDuration] floatValue]; - NSImage *frameImage = [[NSImage alloc] initWithCGImage:bitmapRep.CGImage size:CGSizeZero]; + NSImage *frameImage = [[NSImage alloc] initWithCGImage:bitmapRep.CGImage size:NSZeroSize]; SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:frameImage duration:frameDuration]; [frames addObject:frame]; } @@ -159,6 +187,229 @@ return frames; } ++ (CGColorSpaceRef)colorSpaceGetDeviceRGB { +#if SD_MAC + CGColorSpaceRef screenColorSpace = NSScreen.mainScreen.colorSpace.CGColorSpace; + if (screenColorSpace) { + return screenColorSpace; + } +#endif + static CGColorSpaceRef colorSpace; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ +#if SD_MAC + BOOL shouldUseSRGB = NO; +#else + BOOL shouldUseSRGB = NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_8_x_Max; +#endif + if (shouldUseSRGB) { + // This is what iOS device used colorspace, combined with right bitmapInfo, even without decode, can still avoid extra CA::Render::copy_image(which marked `Color Copied Images` from Instruments) + colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); + } else { + colorSpace = CGColorSpaceCreateDeviceRGB(); + } + }); + return colorSpace; +} + ++ (CGColorSpaceRef)imageRefGetColorSpace:(CGImageRef)imageRef { + // current + CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(CGImageGetColorSpace(imageRef)); + CGColorSpaceRef colorspaceRef = CGImageGetColorSpace(imageRef); + + BOOL unsupportedColorSpace = (imageColorSpaceModel == kCGColorSpaceModelUnknown || + imageColorSpaceModel == kCGColorSpaceModelMonochrome || + imageColorSpaceModel == kCGColorSpaceModelCMYK || + imageColorSpaceModel == kCGColorSpaceModelIndexed); + if (unsupportedColorSpace) { + colorspaceRef = [self colorSpaceGetDeviceRGB]; + } + return colorspaceRef; +} + ++ (BOOL)imageRefContainsAlpha:(CGImageRef)imageRef { + if (!imageRef) { + return NO; + } + CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef); + BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone || + alphaInfo == kCGImageAlphaNoneSkipFirst || + alphaInfo == kCGImageAlphaNoneSkipLast); + return hasAlpha; +} + ++ (CGImageRef)imageRefCreateDecoded:(CGImageRef)imageRef { + if (!imageRef) { + return NULL; + } + size_t width = CGImageGetWidth(imageRef); + size_t height = CGImageGetHeight(imageRef); + if (width == 0 || height == 0) return NULL; + CGRect rect = CGRectMake(0, 0, width, height); + BOOL hasAlpha = [self imageRefContainsAlpha:imageRef]; + // iOS prefer BGRA8888 (premultiplied) or BGRX8888 bitmapInfo for screen rendering, which is same as `UIGraphicsBeginImageContext()` or `- [CALayer drawInContext:]` + // Through you can use any supported bitmapInfo (see: https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html#//apple_ref/doc/uid/TP30001066-CH203-BCIBHHBB ) and let Core Graphics reorder it when you call `CGContextDrawImage` + // But since our build-in coders use this bitmapInfo, this can have a little performance benefit + CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; + bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; + CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, [self colorSpaceGetDeviceRGB], bitmapInfo); + if (!context) { + return NULL; + } + CGContextDrawImage(context, rect, imageRef); + CGImageRef newImageRef = CGBitmapContextCreateImage(context); + CGContextRelease(context); + + return newImageRef; +} + ++ (UIImage *)decodedImageWithImage:(UIImage *)image { +#if SD_MAC + return image; +#else + if (![self shouldDecodeImage:image]) { + return image; + } + + CGImageRef imageRef = [self imageRefCreateDecoded:image.CGImage]; + if (!imageRef) { + return image; + } + UIImage *decodedImage = [[UIImage alloc] initWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation]; + CGImageRelease(imageRef); + return decodedImage; +#endif +} + ++ (UIImage *)decodedAndScaledDownImageWithImage:(UIImage *)image limitBytes:(NSUInteger)bytes { +#if SD_MAC + return image; +#else + if (![self shouldDecodeImage:image]) { + return image; + } + + if (![self shouldScaleDownImage:image limitBytes:bytes]) { + return [self decodedImageWithImage:image]; + } + + CGFloat destTotalPixels; + CGFloat tileTotalPixels; + if (bytes > 0) { + destTotalPixels = bytes / kBytesPerPixel; + tileTotalPixels = destTotalPixels / 3; + } else { + destTotalPixels = kDestTotalPixels; + tileTotalPixels = kTileTotalPixels; + } + CGContextRef destContext; + + // autorelease the bitmap context and all vars to help system to free memory when there are memory warning. + // on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory]; + @autoreleasepool { + CGImageRef sourceImageRef = image.CGImage; + + CGSize sourceResolution = CGSizeZero; + sourceResolution.width = CGImageGetWidth(sourceImageRef); + sourceResolution.height = CGImageGetHeight(sourceImageRef); + float sourceTotalPixels = sourceResolution.width * sourceResolution.height; + // Determine the scale ratio to apply to the input image + // that results in an output image of the defined size. + // see kDestImageSizeMB, and how it relates to destTotalPixels. + float imageScale = destTotalPixels / sourceTotalPixels; + CGSize destResolution = CGSizeZero; + destResolution.width = (int)(sourceResolution.width*imageScale); + destResolution.height = (int)(sourceResolution.height*imageScale); + + // current color space + CGColorSpaceRef colorspaceRef = [self imageRefGetColorSpace:sourceImageRef]; + + // kCGImageAlphaNone is not supported in CGBitmapContextCreate. + // Since the original image here has no alpha info, use kCGImageAlphaNoneSkipFirst + // to create bitmap graphics contexts without alpha info. + destContext = CGBitmapContextCreate(NULL, + destResolution.width, + destResolution.height, + kBitsPerComponent, + 0, + colorspaceRef, + kCGBitmapByteOrder32Host|kCGImageAlphaNoneSkipFirst); + + if (destContext == NULL) { + return image; + } + CGContextSetInterpolationQuality(destContext, kCGInterpolationHigh); + + // Now define the size of the rectangle to be used for the + // incremental blits from the input image to the output image. + // we use a source tile width equal to the width of the source + // image due to the way that iOS retrieves image data from disk. + // iOS must decode an image from disk in full width 'bands', even + // if current graphics context is clipped to a subrect within that + // band. Therefore we fully utilize all of the pixel data that results + // from a decoding opertion by achnoring our tile size to the full + // width of the input image. + CGRect sourceTile = CGRectZero; + sourceTile.size.width = sourceResolution.width; + // The source tile height is dynamic. Since we specified the size + // of the source tile in MB, see how many rows of pixels high it + // can be given the input image width. + sourceTile.size.height = (int)(tileTotalPixels / sourceTile.size.width ); + sourceTile.origin.x = 0.0f; + // The output tile is the same proportions as the input tile, but + // scaled to image scale. + CGRect destTile; + destTile.size.width = destResolution.width; + destTile.size.height = sourceTile.size.height * imageScale; + destTile.origin.x = 0.0f; + // The source seem overlap is proportionate to the destination seem overlap. + // this is the amount of pixels to overlap each tile as we assemble the ouput image. + float sourceSeemOverlap = (int)((kDestSeemOverlap/destResolution.height)*sourceResolution.height); + CGImageRef sourceTileImageRef; + // calculate the number of read/write operations required to assemble the + // output image. + int iterations = (int)( sourceResolution.height / sourceTile.size.height ); + // If tile height doesn't divide the image height evenly, add another iteration + // to account for the remaining pixels. + int remainder = (int)sourceResolution.height % (int)sourceTile.size.height; + if(remainder) { + iterations++; + } + // Add seem overlaps to the tiles, but save the original tile height for y coordinate calculations. + float sourceTileHeightMinusOverlap = sourceTile.size.height; + sourceTile.size.height += sourceSeemOverlap; + destTile.size.height += kDestSeemOverlap; + for( int y = 0; y < iterations; ++y ) { + @autoreleasepool { + sourceTile.origin.y = y * sourceTileHeightMinusOverlap + sourceSeemOverlap; + destTile.origin.y = destResolution.height - (( y + 1 ) * sourceTileHeightMinusOverlap * imageScale + kDestSeemOverlap); + sourceTileImageRef = CGImageCreateWithImageInRect( sourceImageRef, sourceTile ); + if( y == iterations - 1 && remainder ) { + float dify = destTile.size.height; + destTile.size.height = CGImageGetHeight( sourceTileImageRef ) * imageScale; + dify -= destTile.size.height; + destTile.origin.y += dify; + } + CGContextDrawImage( destContext, destTile, sourceTileImageRef ); + CGImageRelease( sourceTileImageRef ); + } + } + + CGImageRef destImageRef = CGBitmapContextCreateImage(destContext); + CGContextRelease(destContext); + if (destImageRef == NULL) { + return image; + } + UIImage *destImage = [[UIImage alloc] initWithCGImage:destImageRef scale:image.scale orientation:image.imageOrientation]; + CGImageRelease(destImageRef); + if (destImage == nil) { + return image; + } + return destImage; + } +#endif +} + #if SD_UIKIT || SD_WATCH // Convert an EXIF image orientation to an iOS one. + (UIImageOrientation)imageOrientationFromEXIFOrientation:(NSInteger)exifOrientation { @@ -233,6 +484,56 @@ #pragma mark - Helper Fuction #if SD_UIKIT || SD_WATCH ++ (BOOL)shouldDecodeImage:(nullable UIImage *)image { + // Prevent "CGBitmapContextCreateImage: invalid context 0x0" error + if (image == nil) { + return NO; + } + // do not decode animated images + if (image.images != nil) { + return NO; + } + CGImageRef imageRef = image.CGImage; + BOOL hasAlpha = [self imageRefContainsAlpha:imageRef]; + // do not decode images with alpha + if (hasAlpha) { + return NO; + } + + return YES; +} + ++ (BOOL)shouldScaleDownImage:(nonnull UIImage *)image limitBytes:(NSUInteger)bytes { + BOOL shouldScaleDown = YES; + + CGImageRef sourceImageRef = image.CGImage; + CGSize sourceResolution = CGSizeZero; + sourceResolution.width = CGImageGetWidth(sourceImageRef); + sourceResolution.height = CGImageGetHeight(sourceImageRef); + float sourceTotalPixels = sourceResolution.width * sourceResolution.height; + if (sourceTotalPixels <= 0) { + return NO; + } + CGFloat destTotalPixels; + if (bytes > 0) { + destTotalPixels = bytes / kBytesPerPixel; + } else { + destTotalPixels = kDestTotalPixels; + } + if (destTotalPixels <= kPixelsPerMB) { + // Too small to scale down + return NO; + } + float imageScale = destTotalPixels / sourceTotalPixels; + if (imageScale < 1) { + shouldScaleDown = YES; + } else { + shouldScaleDown = NO; + } + + return shouldScaleDown; +} + static NSUInteger gcd(NSUInteger a, NSUInteger b) { NSUInteger c; while (a != 0) { diff --git a/SDWebImage/SDWebImageCodersManager.m b/SDWebImage/SDWebImageCodersManager.m index 62c3a363..253cd092 100644 --- a/SDWebImage/SDWebImageCodersManager.m +++ b/SDWebImage/SDWebImageCodersManager.m @@ -12,6 +12,8 @@ #ifdef SD_WEBP #import "SDWebImageWebPCoder.h" #endif +#import "NSImage+Additions.h" +#import "UIImage+WebCache.h" @interface SDWebImageCodersManager () @@ -34,7 +36,7 @@ - (instancetype)init { if (self = [super init]) { // initialize with default coders - _mutableCoders = [@[[SDWebImageImageIOCoder sharedCoder]] mutableCopy]; + _mutableCoders = [@[[SDWebImageImageIOCoder sharedCoder], [SDWebImageGIFCoder sharedCoder]] mutableCopy]; #ifdef SD_WEBP [_mutableCoders addObject:[SDWebImageWebPCoder sharedCoder]]; #endif @@ -92,39 +94,32 @@ return NO; } -- (UIImage *)decodedImageWithData:(NSData *)data { +- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { if (!data) { return nil; } + BOOL decodeFirstFrame = [[options valueForKey:SDWebImageCoderDecodeFirstFrameOnly] boolValue]; + UIImage *image; for (id coder in self.coders) { if ([coder canDecodeFromData:data]) { - return [coder decodedImageWithData:data]; + image = [coder decodedImageWithData:data options:options]; + break; } } - return nil; + if (decodeFirstFrame && image.images.count > 0) { + image = image.images.firstObject; + } + + return image; } -- (UIImage *)decompressedImageWithImage:(UIImage *)image - data:(NSData *__autoreleasing _Nullable *)data - options:(nullable NSDictionary*)optionsDict { - if (!image) { - return nil; - } - for (id coder in self.coders) { - if ([coder canDecodeFromData:*data]) { - return [coder decompressedImageWithImage:image data:data options:optionsDict]; - } - } - return nil; -} - -- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format { +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDWebImageCoderOptions *)options { if (!image) { return nil; } for (id coder in self.coders) { if ([coder canEncodeToFormat:format]) { - return [coder encodedDataWithImage:image format:format]; + return [coder encodedDataWithImage:image format:format options:nil]; } } return nil; diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 1ee0c7c9..bb6baf14 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -10,6 +10,7 @@ #import "SDWebImageManager.h" #import "NSImage+Additions.h" #import "SDWebImageCodersManager.h" +#import "SDWebImageCoderHelper.h" #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); #define UNLOCK(lock) dispatch_semaphore_signal(lock); @@ -361,7 +362,7 @@ didReceiveResponse:(NSURLResponse *)response NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; image = [self scaledImageForKey:key image:image]; if (self.shouldDecompressImages) { - image = [[SDWebImageCodersManager sharedManager] decompressedImageWithImage:image data:&imageData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}]; + image = [SDWebImageCoderHelper decodedImageWithImage:image]; } // We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding. @@ -427,7 +428,7 @@ didReceiveResponse:(NSURLResponse *)response } else { // decode the image in coder queue dispatch_async(self.coderQueue, ^{ - UIImage *image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData]; + UIImage *image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:nil]; NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; image = [self scaledImageForKey:key image:image]; @@ -435,19 +436,15 @@ didReceiveResponse:(NSURLResponse *)response // Do not force decoding animated GIFs and WebPs if (image.images) { shouldDecode = NO; - } else { -#ifdef SD_WEBP - SDImageFormat imageFormat = [NSData sd_imageFormatForImageData:imageData]; - if (imageFormat == SDImageFormatWebP) { - shouldDecode = NO; - } -#endif } - if (shouldDecode) { if (self.shouldDecompressImages) { BOOL shouldScaleDown = self.options & SDWebImageDownloaderScaleDownLargeImages; - image = [[SDWebImageCodersManager sharedManager] decompressedImageWithImage:image data:&imageData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(shouldScaleDown)}]; + if (shouldScaleDown) { + image = [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; + } else { + image = [SDWebImageCoderHelper decodedImageWithImage:image]; + } } } CGSize imageSize = image.size; diff --git a/SDWebImage/SDWebImageGIFCoder.h b/SDWebImage/SDWebImageGIFCoder.h index f6a3dc5d..84a9cb69 100644 --- a/SDWebImage/SDWebImageGIFCoder.h +++ b/SDWebImage/SDWebImageGIFCoder.h @@ -12,11 +12,10 @@ /** Built in coder using ImageIO that supports GIF encoding/decoding @note `SDWebImageIOCoder` supports GIF but only as static (will use the 1st frame). - @note Use `SDWebImageGIFCoder` for fully animated GIFs - less performant than `FLAnimatedImage` - @note If you decide to make all `UIImageView`(including `FLAnimatedImageView`) instance support GIF. You should add this coder to `SDWebImageCodersManager` and make sure that it has a higher priority than `SDWebImageIOCoder` - @note The recommended approach for animated GIFs is using `FLAnimatedImage`. It's more performant than `UIImageView` for GIF displaying + @note Use `SDWebImageGIFCoder` for fully animated GIFs. For `UIImageView`, it will produce animated `UIImage`(`NSImage` on macOS) for rendering. For `SDAnimatedImageView`, it will use `SDAnimatedImage` for rendering. + @note The recommended approach for animated GIFs is using `SDAnimatedImage` with `SDAnimatedImageView`. It's more performant than `UIImageView` for GIF displaying(especially on memory usage) */ -@interface SDWebImageGIFCoder : NSObject +@interface SDWebImageGIFCoder : NSObject @property (nonatomic, class, readonly, nonnull) SDWebImageGIFCoder *sharedCoder; diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index 934b21e6..3ff30d6f 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -14,7 +14,47 @@ #import "SDWebImageCoderHelper.h" #import "SDAnimatedImageRep.h" -@implementation SDWebImageGIFCoder +@interface SDGIFCoderFrame : NSObject + +@property (nonatomic, assign) NSUInteger index; // Frame index (zero based) +@property (nonatomic, assign) NSTimeInterval duration; // Frame duration in seconds + +@end + +@implementation SDGIFCoderFrame +@end + +@implementation SDWebImageGIFCoder { + size_t _width, _height; +#if SD_UIKIT || SD_WATCH + UIImageOrientation _orientation; +#endif + CGImageSourceRef _imageSource; + NSData *_imageData; + NSUInteger _loopCount; + NSUInteger _frameCount; + NSArray *_frames; +} + +- (void)dealloc +{ + if (_imageSource) { + CFRelease(_imageSource); + _imageSource = NULL; + } +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif +} + +- (void)didReceiveMemoryWarning:(NSNotification *)notification +{ + if (_imageSource) { + for (size_t i = 0; i < _frameCount; i++) { + CGImageSourceRemoveCacheAtIndex(_imageSource, i); + } + } +} + (instancetype)sharedCoder { static SDWebImageGIFCoder *coder; @@ -30,7 +70,7 @@ return ([NSData sd_imageFormatForImageData:data] == SDImageFormatGIF); } -- (UIImage *)decodedImageWithData:(NSData *)data { +- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable NSDictionary *)optionsDict { if (!data) { return nil; } @@ -50,7 +90,8 @@ UIImage *animatedImage; - if (count <= 1) { + BOOL decodeFirstFrame = [optionsDict[SDWebImageCoderDecodeFirstFrameOnly] boolValue]; + if (decodeFirstFrame || count <= 1) { animatedImage = [[UIImage alloc] initWithData:data]; } else { NSMutableArray *frames = [NSMutableArray array]; @@ -69,15 +110,7 @@ [frames addObject:frame]; } - NSUInteger loopCount = 1; - NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(source, nil); - NSDictionary *gifProperties = [imageProperties valueForKey:(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary]; - if (gifProperties) { - NSNumber *gifLoopCount = [gifProperties valueForKey:(__bridge_transfer NSString *)kCGImagePropertyGIFLoopCount]; - if (gifLoopCount != nil) { - loopCount = gifLoopCount.unsignedIntegerValue; - } - } + NSUInteger loopCount = [self sd_imageLoopCountWithSource:source]; animatedImage = [SDWebImageCoderHelper animatedImageWithFrames:frames]; animatedImage.sd_imageLoopCount = loopCount; @@ -89,6 +122,19 @@ #endif } +- (NSUInteger)sd_imageLoopCountWithSource:(CGImageSourceRef)source { + NSUInteger loopCount = 1; + NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(source, nil); + NSDictionary *gifProperties = [imageProperties valueForKey:(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary]; + if (gifProperties) { + NSNumber *gifLoopCount = [gifProperties valueForKey:(__bridge_transfer NSString *)kCGImagePropertyGIFLoopCount]; + if (gifLoopCount != nil) { + loopCount = gifLoopCount.unsignedIntegerValue; + } + } + return loopCount; +} + - (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source { float frameDuration = 0.1f; CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil); @@ -121,19 +167,12 @@ return frameDuration; } -- (UIImage *)decompressedImageWithImage:(UIImage *)image - data:(NSData *__autoreleasing _Nullable *)data - options:(nullable NSDictionary*)optionsDict { - // GIF do not decompress - return image; -} - #pragma mark - Encode - (BOOL)canEncodeToFormat:(SDImageFormat)format { return (format == SDImageFormatGIF); } -- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format { +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDWebImageCoderOptions *)options { if (!image) { return nil; } @@ -180,4 +219,98 @@ return [imageData copy]; } +#pragma mark - SDWebImageAnimatedCoder +- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data { + if (!data) { + return nil; + } + self = [super init]; + if (self) { + // use Image/IO cache because it's already keep a balance between CPU & memory + CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)}); + if (!imageSource) { + return nil; + } + BOOL framesValid = [self scanAndCheckFramesValidWithImageSource:imageSource]; + if (!framesValid) { + CFRelease(imageSource); + return nil; + } + _imageSource = imageSource; + _imageData = data; +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif + } + return self; +} + +- (BOOL)scanAndCheckFramesValidWithImageSource:(CGImageSourceRef)imageSource +{ + if (!imageSource) { + return NO; + } + NSUInteger frameCount = CGImageSourceGetCount(imageSource); + NSUInteger loopCount = [self sd_imageLoopCountWithSource:imageSource]; + NSMutableArray *frames = [NSMutableArray array]; + + for (size_t i = 0; i < frameCount; i++) { + SDGIFCoderFrame *frame = [[SDGIFCoderFrame alloc] init]; + frame.index = i; + frame.duration = [self sd_frameDurationAtIndex:i source:imageSource]; + [frames addObject:frame]; + } + + _frameCount = frameCount; + _loopCount = loopCount; + _frames = [frames copy]; + + return YES; +} + +- (NSData *)animatedImageData +{ + return _imageData; +} + +- (NSUInteger)animatedImageLoopCount +{ + return _loopCount; +} + +- (NSUInteger)animatedImageFrameCount +{ + return _frameCount; +} + +- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index +{ + if (index >= _frameCount) { + return 0; + } + return _frames[index].duration; +} + +- (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index +{ + CGImageRef imageRef = CGImageSourceCreateImageAtIndex(_imageSource, index, NULL); + if (!imageRef) { + return nil; + } + // Image/IO create CGImage does not decode, so we do this because this is called background queue, this can avoid main queue block when rendering(especially when one more imageViews use the same image instance) + CGImageRef newImageRef = [SDWebImageCoderHelper imageRefCreateDecoded:imageRef]; + if (!newImageRef) { + newImageRef = imageRef; + } else { + CGImageRelease(imageRef); + } +#if SD_MAC + UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef size:NSZeroSize]; +#else + UIImage *image = [UIImage imageWithCGImage:newImageRef]; +#endif + CGImageRelease(newImageRef); + return image; +} + @end diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index ecce4446..efc98c8f 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -12,40 +12,13 @@ #import #import "NSData+ImageContentType.h" -#if SD_UIKIT || SD_WATCH -static const size_t kBytesPerPixel = 4; -static const size_t kBitsPerComponent = 8; - -/* - * Defines the maximum size in MB of the decoded image when the flag `SDWebImageScaleDownLargeImages` is set - * Suggested value for iPad1 and iPhone 3GS: 60. - * Suggested value for iPad2 and iPhone 4: 120. - * Suggested value for iPhone 3G and iPod 2 and earlier devices: 30. - */ -static const CGFloat kDestImageSizeMB = 60.0f; - -/* - * Defines the maximum size in MB of a tile used to decode image when the flag `SDWebImageScaleDownLargeImages` is set - * Suggested value for iPad1 and iPhone 3GS: 20. - * Suggested value for iPad2 and iPhone 4: 40. - * Suggested value for iPhone 3G and iPod 2 and earlier devices: 10. - */ -static const CGFloat kSourceImageTileSizeMB = 20.0f; - -static const CGFloat kBytesPerMB = 1024.0f * 1024.0f; -static const CGFloat kPixelsPerMB = kBytesPerMB / kBytesPerPixel; -static const CGFloat kDestTotalPixels = kDestImageSizeMB * kPixelsPerMB; -static const CGFloat kTileTotalPixels = kSourceImageTileSizeMB * kPixelsPerMB; - -static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to overlap the seems where tiles meet. -#endif - @implementation SDWebImageImageIOCoder { - size_t _width, _height; + size_t _width, _height; #if SD_UIKIT || SD_WATCH - UIImageOrientation _orientation; + UIImageOrientation _orientation; #endif - CGImageSourceRef _imageSource; + CGImageSourceRef _imageSource; + NSUInteger _frameCount; } - (void)dealloc { @@ -53,6 +26,18 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over CFRelease(_imageSource); _imageSource = NULL; } +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif +} + +- (void)didReceiveMemoryWarning:(NSNotification *)notification +{ + if (_imageSource) { + for (size_t i = 0; i < _frameCount; i++) { + CGImageSourceRemoveCacheAtIndex(_imageSource, i); + } + } } + (instancetype)sharedCoder { @@ -91,7 +76,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over } } -- (UIImage *)decodedImageWithData:(NSData *)data { +- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { if (!data) { return nil; } @@ -114,10 +99,19 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over #endif } -- (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished { - if (!_imageSource) { +#pragma mark - Progressive Decode +- (instancetype)initIncrementally { + self = [super init]; + if (self) { _imageSource = CGImageSourceCreateIncremental(NULL); +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif } + return self; +} + +- (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished { UIImage *image; // The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/ @@ -125,6 +119,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over // Update the data source, we must pass ALL the data, not just the new bytes CGImageSourceUpdateData(_imageSource, (__bridge CFDataRef)data, finished); + _frameCount = CGImageSourceGetCount(_imageSource); if (_width + _height == 0) { CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(_imageSource, 0, NULL); @@ -156,8 +151,8 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over // Workaround for iOS anamorphic image if (partialImageRef) { const size_t partialHeight = CGImageGetHeight(partialImageRef); - CGColorSpaceRef colorSpace = SDCGColorSpaceGetDeviceRGB(); - CGContextRef bmContext = CGBitmapContextCreate(NULL, _width, _height, 8, 0, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst); + CGColorSpaceRef colorSpace = [SDWebImageCoderHelper colorSpaceGetDeviceRGB]; + CGContextRef bmContext = CGBitmapContextCreate(NULL, _width, _height, 8, 0, colorSpace, kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst); if (bmContext) { CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = _width, .size.height = partialHeight}, partialImageRef); CGImageRelease(partialImageRef); @@ -191,198 +186,6 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over return image; } -- (UIImage *)decompressedImageWithImage:(UIImage *)image - data:(NSData *__autoreleasing _Nullable *)data - options:(nullable NSDictionary*)optionsDict { -#if SD_MAC - return image; -#endif -#if SD_UIKIT || SD_WATCH - BOOL shouldScaleDown = NO; - if (optionsDict != nil) { - NSNumber *scaleDownLargeImagesOption = nil; - if ([optionsDict[SDWebImageCoderScaleDownLargeImagesKey] isKindOfClass:[NSNumber class]]) { - scaleDownLargeImagesOption = (NSNumber *)optionsDict[SDWebImageCoderScaleDownLargeImagesKey]; - } - if (scaleDownLargeImagesOption != nil) { - shouldScaleDown = [scaleDownLargeImagesOption boolValue]; - } - } - if (!shouldScaleDown) { - return [self sd_decompressedImageWithImage:image]; - } else { - UIImage *scaledDownImage = [self sd_decompressedAndScaledDownImageWithImage:image]; - if (scaledDownImage && !CGSizeEqualToSize(scaledDownImage.size, image.size)) { - // if the image is scaled down, need to modify the data pointer as well - SDImageFormat format = [NSData sd_imageFormatForImageData:*data]; - NSData *imageData = [self encodedDataWithImage:scaledDownImage format:format]; - if (imageData) { - *data = imageData; - } - } - return scaledDownImage; - } -#endif -} - -#if SD_UIKIT || SD_WATCH -- (nullable UIImage *)sd_decompressedImageWithImage:(nullable UIImage *)image { - if (![[self class] shouldDecodeImage:image]) { - return image; - } - - // autorelease the bitmap context and all vars to help system to free memory when there are memory warning. - // on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory]; - @autoreleasepool{ - - CGImageRef imageRef = image.CGImage; - CGColorSpaceRef colorspaceRef = [[self class] colorSpaceForImageRef:imageRef]; - - size_t width = CGImageGetWidth(imageRef); - size_t height = CGImageGetHeight(imageRef); - - // kCGImageAlphaNone is not supported in CGBitmapContextCreate. - // Since the original image here has no alpha info, use kCGImageAlphaNoneSkipLast - // to create bitmap graphics contexts without alpha info. - CGContextRef context = CGBitmapContextCreate(NULL, - width, - height, - kBitsPerComponent, - 0, - colorspaceRef, - kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast); - if (context == NULL) { - return image; - } - - // Draw the image into the context and retrieve the new bitmap image without alpha - CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); - CGImageRef imageRefWithoutAlpha = CGBitmapContextCreateImage(context); - UIImage *imageWithoutAlpha = [[UIImage alloc] initWithCGImage:imageRefWithoutAlpha scale:image.scale orientation:image.imageOrientation]; - CGContextRelease(context); - CGImageRelease(imageRefWithoutAlpha); - - return imageWithoutAlpha; - } -} - -- (nullable UIImage *)sd_decompressedAndScaledDownImageWithImage:(nullable UIImage *)image { - if (![[self class] shouldDecodeImage:image]) { - return image; - } - - if (![[self class] shouldScaleDownImage:image]) { - return [self sd_decompressedImageWithImage:image]; - } - - CGContextRef destContext; - - // autorelease the bitmap context and all vars to help system to free memory when there are memory warning. - // on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory]; - @autoreleasepool { - CGImageRef sourceImageRef = image.CGImage; - - CGSize sourceResolution = CGSizeZero; - sourceResolution.width = CGImageGetWidth(sourceImageRef); - sourceResolution.height = CGImageGetHeight(sourceImageRef); - float sourceTotalPixels = sourceResolution.width * sourceResolution.height; - // Determine the scale ratio to apply to the input image - // that results in an output image of the defined size. - // see kDestImageSizeMB, and how it relates to destTotalPixels. - float imageScale = kDestTotalPixels / sourceTotalPixels; - CGSize destResolution = CGSizeZero; - destResolution.width = (int)(sourceResolution.width*imageScale); - destResolution.height = (int)(sourceResolution.height*imageScale); - - // current color space - CGColorSpaceRef colorspaceRef = [[self class] colorSpaceForImageRef:sourceImageRef]; - - // kCGImageAlphaNone is not supported in CGBitmapContextCreate. - // Since the original image here has no alpha info, use kCGImageAlphaNoneSkipLast - // to create bitmap graphics contexts without alpha info. - destContext = CGBitmapContextCreate(NULL, - destResolution.width, - destResolution.height, - kBitsPerComponent, - 0, - colorspaceRef, - kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast); - - if (destContext == NULL) { - return image; - } - CGContextSetInterpolationQuality(destContext, kCGInterpolationHigh); - - // Now define the size of the rectangle to be used for the - // incremental blits from the input image to the output image. - // we use a source tile width equal to the width of the source - // image due to the way that iOS retrieves image data from disk. - // iOS must decode an image from disk in full width 'bands', even - // if current graphics context is clipped to a subrect within that - // band. Therefore we fully utilize all of the pixel data that results - // from a decoding opertion by achnoring our tile size to the full - // width of the input image. - CGRect sourceTile = CGRectZero; - sourceTile.size.width = sourceResolution.width; - // The source tile height is dynamic. Since we specified the size - // of the source tile in MB, see how many rows of pixels high it - // can be given the input image width. - sourceTile.size.height = (int)(kTileTotalPixels / sourceTile.size.width ); - sourceTile.origin.x = 0.0f; - // The output tile is the same proportions as the input tile, but - // scaled to image scale. - CGRect destTile; - destTile.size.width = destResolution.width; - destTile.size.height = sourceTile.size.height * imageScale; - destTile.origin.x = 0.0f; - // The source seem overlap is proportionate to the destination seem overlap. - // this is the amount of pixels to overlap each tile as we assemble the ouput image. - float sourceSeemOverlap = (int)((kDestSeemOverlap/destResolution.height)*sourceResolution.height); - CGImageRef sourceTileImageRef; - // calculate the number of read/write operations required to assemble the - // output image. - int iterations = (int)( sourceResolution.height / sourceTile.size.height ); - // If tile height doesn't divide the image height evenly, add another iteration - // to account for the remaining pixels. - int remainder = (int)sourceResolution.height % (int)sourceTile.size.height; - if(remainder) { - iterations++; - } - // Add seem overlaps to the tiles, but save the original tile height for y coordinate calculations. - float sourceTileHeightMinusOverlap = sourceTile.size.height; - sourceTile.size.height += sourceSeemOverlap; - destTile.size.height += kDestSeemOverlap; - for( int y = 0; y < iterations; ++y ) { - @autoreleasepool { - sourceTile.origin.y = y * sourceTileHeightMinusOverlap + sourceSeemOverlap; - destTile.origin.y = destResolution.height - (( y + 1 ) * sourceTileHeightMinusOverlap * imageScale + kDestSeemOverlap); - sourceTileImageRef = CGImageCreateWithImageInRect( sourceImageRef, sourceTile ); - if( y == iterations - 1 && remainder ) { - float dify = destTile.size.height; - destTile.size.height = CGImageGetHeight( sourceTileImageRef ) * imageScale; - dify -= destTile.size.height; - destTile.origin.y += dify; - } - CGContextDrawImage( destContext, destTile, sourceTileImageRef ); - CGImageRelease( sourceTileImageRef ); - } - } - - CGImageRef destImageRef = CGBitmapContextCreateImage(destContext); - CGContextRelease(destContext); - if (destImageRef == NULL) { - return image; - } - UIImage *destImage = [[UIImage alloc] initWithCGImage:destImageRef scale:image.scale orientation:image.imageOrientation]; - CGImageRelease(destImageRef); - if (destImage == nil) { - return image; - } - return destImage; - } -} -#endif - #pragma mark - Encode - (BOOL)canEncodeToFormat:(SDImageFormat)format { switch (format) { @@ -397,13 +200,13 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over } } -- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format { +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDWebImageCoderOptions *)options { if (!image) { return nil; } if (format == SDImageFormatUndefined) { - BOOL hasAlpha = SDCGImageRefContainsAlpha(image.CGImage); + BOOL hasAlpha = [SDWebImageCoderHelper imageRefContainsAlpha:image.CGImage]; if (hasAlpha) { format = SDImageFormatPNG; } else { @@ -441,29 +244,6 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over return [imageData copy]; } -#pragma mark - Helper -+ (BOOL)shouldDecodeImage:(nullable UIImage *)image { - // Prevent "CGBitmapContextCreateImage: invalid context 0x0" error - if (image == nil) { - return NO; - } - - // do not decode animated images - if (image.images != nil) { - return NO; - } - - CGImageRef imageRef = image.CGImage; - - BOOL hasAlpha = SDCGImageRefContainsAlpha(imageRef); - // do not decode images with alpha - if (hasAlpha) { - return NO; - } - - return YES; -} - + (BOOL)canDecodeFromHEICFormat { static BOOL canDecode = NO; static dispatch_once_t onceToken; @@ -538,39 +318,4 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over } #endif -#if SD_UIKIT || SD_WATCH -+ (BOOL)shouldScaleDownImage:(nonnull UIImage *)image { - BOOL shouldScaleDown = YES; - - CGImageRef sourceImageRef = image.CGImage; - CGSize sourceResolution = CGSizeZero; - sourceResolution.width = CGImageGetWidth(sourceImageRef); - sourceResolution.height = CGImageGetHeight(sourceImageRef); - float sourceTotalPixels = sourceResolution.width * sourceResolution.height; - float imageScale = kDestTotalPixels / sourceTotalPixels; - if (imageScale < 1) { - shouldScaleDown = YES; - } else { - shouldScaleDown = NO; - } - - return shouldScaleDown; -} - -+ (CGColorSpaceRef)colorSpaceForImageRef:(CGImageRef)imageRef { - // current - CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(CGImageGetColorSpace(imageRef)); - CGColorSpaceRef colorspaceRef = CGImageGetColorSpace(imageRef); - - BOOL unsupportedColorSpace = (imageColorSpaceModel == kCGColorSpaceModelUnknown || - imageColorSpaceModel == kCGColorSpaceModelMonochrome || - imageColorSpaceModel == kCGColorSpaceModelCMYK || - imageColorSpaceModel == kCGColorSpaceModelIndexed); - if (unsupportedColorSpace) { - colorspaceRef = SDCGColorSpaceGetDeviceRGB(); - } - return colorspaceRef; -} -#endif - @end diff --git a/SDWebImage/SDWebImageWebPCoder.h b/SDWebImage/SDWebImageWebPCoder.h index 05f51856..052c6fc0 100644 --- a/SDWebImage/SDWebImageWebPCoder.h +++ b/SDWebImage/SDWebImageWebPCoder.h @@ -14,7 +14,7 @@ /** Built in coder that supports WebP and animated WebP */ -@interface SDWebImageWebPCoder : NSObject +@interface SDWebImageWebPCoder : NSObject @property (nonatomic, class, readonly, nonnull) SDWebImageWebPCoder *sharedCoder; diff --git a/SDWebImage/SDWebImageWebPCoder.m b/SDWebImage/SDWebImageWebPCoder.m index 91259d1b..536c3526 100644 --- a/SDWebImage/SDWebImageWebPCoder.m +++ b/SDWebImage/SDWebImageWebPCoder.m @@ -24,8 +24,43 @@ #import "webp/mux.h" #endif +#define LOCK(...) dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER); \ +__VA_ARGS__; \ +dispatch_semaphore_signal(self->_lock); + +@interface SDWebPCoderFrame : NSObject + +@property (nonatomic, assign) NSUInteger index; // Frame index (zero based) +@property (nonatomic, assign) NSTimeInterval duration; // Frame duration in seconds +@property (nonatomic, assign) NSUInteger width; // Frame width +@property (nonatomic, assign) NSUInteger height; // Frame height +@property (nonatomic, assign) NSUInteger offsetX; // Frame origin.x in canvas (left-bottom based) +@property (nonatomic, assign) NSUInteger offsetY; // Frame origin.y in canvas (left-bottom based) +@property (nonatomic, assign) BOOL hasAlpha; // Whether frame contains alpha +@property (nonatomic, assign) BOOL isFullSize; // Whether frame size is equal to canvas size +@property (nonatomic, assign) WebPMuxAnimBlend blend; // Frame dispose method +@property (nonatomic, assign) WebPMuxAnimDispose dispose; // Frame blend operation +@property (nonatomic, assign) NSUInteger blendFromIndex; // The nearest previous frame index which blend mode is WEBP_MUX_BLEND + +@end + +@implementation SDWebPCoderFrame +@end + @implementation SDWebImageWebPCoder { WebPIDecoder *_idec; + WebPDemuxer *_demux; + NSData *_imageData; + NSUInteger _loopCount; + NSUInteger _frameCount; + NSArray *_frames; + CGContextRef _canvas; + BOOL _hasAnimation; + BOOL _hasAlpha; + CGFloat _canvasWidth; + CGFloat _canvasHeight; + dispatch_semaphore_t _lock; + NSUInteger _currentBlendIndex; } - (void)dealloc { @@ -33,6 +68,14 @@ WebPIDelete(_idec); _idec = NULL; } + if (_demux) { + WebPDemuxDelete(_demux); + _demux = NULL; + } + if (_canvas) { + CGContextRelease(_canvas); + _canvas = NULL; + } } + (instancetype)sharedCoder { @@ -53,7 +96,7 @@ return ([NSData sd_imageFormatForImageData:data] == SDImageFormatWebP); } -- (UIImage *)decodedImageWithData:(NSData *)data { +- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable NSDictionary *)optionsDict { if (!data) { return nil; } @@ -68,49 +111,41 @@ } uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS); - int loopCount = WebPDemuxGetI(demuxer, WEBP_FF_LOOP_COUNT); - int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH); - int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT); - CGBitmapInfo bitmapInfo; - if (!(flags & ALPHA_FLAG)) { - bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaNoneSkipLast; - } else { - bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast; - } - CGContextRef canvas = CGBitmapContextCreate(NULL, canvasWidth, canvasHeight, 8, 0, SDCGColorSpaceGetDeviceRGB(), bitmapInfo); - if (!canvas) { - WebPDemuxDelete(demuxer); - return nil; - } - - if (!(flags & ANIMATION_FLAG)) { + BOOL hasAnimation = flags & ANIMATION_FLAG; + BOOL decodeFirstFrame = [[optionsDict valueForKey:SDWebImageCoderDecodeFirstFrameOnly] boolValue]; + if (!hasAnimation) { // for static single webp image UIImage *staticImage = [self sd_rawWebpImageWithData:webpData]; - if (staticImage) { - // draw on CGBitmapContext can reduce memory usage - CGImageRef imageRef = staticImage.CGImage; - size_t width = CGImageGetWidth(imageRef); - size_t height = CGImageGetHeight(imageRef); - CGContextDrawImage(canvas, CGRectMake(0, 0, width, height), imageRef); - CGImageRef newImageRef = CGBitmapContextCreateImage(canvas); -#if SD_UIKIT || SD_WATCH - staticImage = [[UIImage alloc] initWithCGImage:newImageRef]; -#else - staticImage = [[UIImage alloc] initWithCGImage:newImageRef size:NSZeroSize]; -#endif - CGImageRelease(newImageRef); - } WebPDemuxDelete(demuxer); - CGContextRelease(canvas); return staticImage; } // for animated webp image WebPIterator iter; + // libwebp's index start with 1 if (!WebPDemuxGetFrame(demuxer, 1, &iter)) { WebPDemuxReleaseIterator(&iter); WebPDemuxDelete(demuxer); - CGContextRelease(canvas); + return nil; + } + + if (decodeFirstFrame) { + // first frame for animated webp image + UIImage *firstFrameImage = [self sd_rawWebpImageWithData:iter.fragment]; + WebPDemuxReleaseIterator(&iter); + WebPDemuxDelete(demuxer); + return firstFrameImage; + } + + int loopCount = WebPDemuxGetI(demuxer, WEBP_FF_LOOP_COUNT); + int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH); + int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT); + BOOL hasAlpha = flags & ALPHA_FLAG; + CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; + bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; + CGContextRef canvas = CGBitmapContextCreate(NULL, canvasWidth, canvasHeight, 8, 0, [SDWebImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo); + if (!canvas) { + WebPDemuxDelete(demuxer); return nil; } @@ -123,13 +158,8 @@ continue; } - int duration = iter.duration; - if (duration <= 10) { - // WebP standard says 0 duration is used for canvas updating but not showing image, but actually Chrome and other implementations set it to 100ms if duration is lower or equal than 10ms - // Some animated WebP images also created without duration, we should keep compatibility - duration = 100; - } - SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:image duration:duration / 1000.f]; + NSTimeInterval duration = [self sd_frameDurationWithIterator:iter]; + SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:image duration:duration]; [frames addObject:frame]; } @@ -145,15 +175,20 @@ return animatedImage; } +#pragma mark - Progressive Decode +- (instancetype)initIncrementally { + self = [super init]; + if (self) { + // Progressive images need transparent, so always use premultiplied RGBA + _idec = WebPINewRGB(MODE_bgrA, NULL, 0, 0); + } + return self; +} + - (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished { if (!_idec) { - // Progressive images need transparent, so always use premultiplied RGBA - _idec = WebPINewRGB(MODE_rgbA, NULL, 0, 0); - if (!_idec) { - return nil; - } + return nil; } - UIImage *image; VP8StatusCode status = WebPIUpdate(_idec, data.bytes, data.length); @@ -172,9 +207,9 @@ size_t rgbaSize = last_y * stride; CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, rgba, rgbaSize, NULL); - CGColorSpaceRef colorSpaceRef = SDCGColorSpaceGetDeviceRGB(); + CGColorSpaceRef colorSpaceRef = [SDWebImageCoderHelper colorSpaceGetDeviceRGB]; - CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast; + CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst; size_t components = 4; CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; // Why to use last_y for image height is because of libwebp's bug (https://bugs.chromium.org/p/webp/issues/detail?id=362) @@ -191,7 +226,7 @@ return nil; } - CGContextRef canvas = CGBitmapContextCreate(NULL, width, height, 8, 0, SDCGColorSpaceGetDeviceRGB(), bitmapInfo); + CGContextRef canvas = CGBitmapContextCreate(NULL, width, height, 8, 0, [SDWebImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo); if (!canvas) { CGImageRelease(imageRef); return nil; @@ -225,11 +260,26 @@ return image; } -- (UIImage *)decompressedImageWithImage:(UIImage *)image - data:(NSData *__autoreleasing _Nullable *)data - options:(nullable NSDictionary*)optionsDict { - // WebP do not decompress - return image; +- (void)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter { + size_t canvasHeight = CGBitmapContextGetHeight(canvas); + CGFloat tmpX = iter.x_offset; + CGFloat tmpY = canvasHeight - iter.height - iter.y_offset; + CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height); + + if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { + CGContextClearRect(canvas, imageRect); + } else { + UIImage *image = [self sd_rawWebpImageWithData:iter.fragment]; + if (!image) { + return; + } + BOOL shouldBlend = iter.blend_method == WEBP_MUX_BLEND; + // If not blend, cover the target image rect. (firstly clear then draw) + if (!shouldBlend) { + CGContextClearRect(canvas, imageRect); + } + CGContextDrawImage(canvas, imageRect, image.CGImage); + } } - (nullable UIImage *)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter { @@ -238,11 +288,9 @@ return nil; } - size_t canvasWidth = CGBitmapContextGetWidth(canvas); size_t canvasHeight = CGBitmapContextGetHeight(canvas); - CGSize size = CGSizeMake(canvasWidth, canvasHeight); CGFloat tmpX = iter.x_offset; - CGFloat tmpY = size.height - iter.height - iter.y_offset; + CGFloat tmpY = canvasHeight - iter.height - iter.y_offset; CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height); BOOL shouldBlend = iter.blend_method == WEBP_MUX_BLEND; @@ -278,8 +326,14 @@ return nil; } - config.output.colorspace = config.input.has_alpha ? MODE_rgbA : MODE_RGB; + BOOL hasAlpha = config.input.has_alpha; + // iOS prefer BGRA8888 (premultiplied) or BGRX8888 bitmapInfo for screen rendering, which is same as `UIGraphicsBeginImageContext()` or `- [CALayer drawInContext:]` + // use this bitmapInfo, combined with right colorspace, even without decode, can still avoid extra CA::Render::copy_image(which marked `Color Copied Images` from Instruments) + WEBP_CSP_MODE colorspace = MODE_bgrA; + CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; + bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; config.options.use_threads = 1; + config.output.colorspace = colorspace; // Decode the WebP image data into a RGBA value array if (WebPDecode(webpData.bytes, webpData.size, &config) != VP8_STATUS_OK) { @@ -296,11 +350,12 @@ // Construct a UIImage from the decoded RGBA value array CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, config.output.u.RGBA.rgba, config.output.u.RGBA.size, FreeImageData); - CGColorSpaceRef colorSpaceRef = SDCGColorSpaceGetDeviceRGB(); - CGBitmapInfo bitmapInfo = config.input.has_alpha ? kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast : kCGBitmapByteOrder32Big | kCGImageAlphaNoneSkipLast; - size_t components = config.input.has_alpha ? 4 : 3; + size_t bitsPerComponent = 8; + size_t bitsPerPixel = 32; + size_t bytesPerRow = config.output.u.RGBA.stride; + CGColorSpaceRef colorSpaceRef = [SDWebImageCoderHelper colorSpaceGetDeviceRGB]; CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; - CGImageRef imageRef = CGImageCreate(width, height, 8, components * 8, components * width, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); + CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); CGDataProviderRelease(provider); @@ -314,12 +369,22 @@ return image; } +- (NSTimeInterval)sd_frameDurationWithIterator:(WebPIterator)iter { + int duration = iter.duration; + if (duration <= 10) { + // WebP standard says 0 duration is used for canvas updating but not showing image, but actually Chrome and other implementations set it to 100ms if duration is lower or equal than 10ms + // Some animated WebP images also created without duration, we should keep compatibility + duration = 100; + } + return duration / 1000.0; +} + #pragma mark - Encode - (BOOL)canEncodeToFormat:(SDImageFormat)format { return (format == SDImageFormatWebP); } -- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format { +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDWebImageCoderOptions *)options { if (!image) { return nil; } @@ -421,6 +486,187 @@ static void FreeImageData(void *info, const void *data, size_t size) { free((void *)data); } +#pragma mark - SDWebImageAnimatedCoder +- (instancetype)initWithAnimatedImageData:(NSData *)data { + if (!data) { + return nil; + } + if (self) { + WebPData webpData; + WebPDataInit(&webpData); + webpData.bytes = data.bytes; + webpData.size = data.length; + WebPDemuxer *demuxer = WebPDemux(&webpData); + if (!demuxer) { + return nil; + } + BOOL framesValid = [self scanAndCheckFramesValidWithDemuxer:demuxer]; + if (!framesValid) { + WebPDemuxDelete(demuxer); + return nil; + } + _demux = demuxer; + _imageData = data; + _currentBlendIndex = NSNotFound; + _lock = dispatch_semaphore_create(1); + } + return self; +} + +- (BOOL)scanAndCheckFramesValidWithDemuxer:(WebPDemuxer *)demuxer +{ + if (!demuxer) { + return NO; + } + WebPIterator iter; + if (!WebPDemuxGetFrame(demuxer, 1, &iter)) { + WebPDemuxReleaseIterator(&iter); + return NO; + } + + uint32_t iterIndex = 0; + uint32_t lastBlendIndex = 0; + uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS); + BOOL hasAnimation = flags & ANIMATION_FLAG; + BOOL hasAlpha = flags & ALPHA_FLAG; + int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH); + int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT); + uint32_t frameCount = WebPDemuxGetI(demuxer, WEBP_FF_FRAME_COUNT); + uint32_t loopCount = WebPDemuxGetI(demuxer, WEBP_FF_LOOP_COUNT); + NSMutableArray *frames = [NSMutableArray array]; + + // We should loop all the frames and scan each frames' blendFromIndex for later decoding, this can also ensure all frames is valid + do { + SDWebPCoderFrame *frame = [[SDWebPCoderFrame alloc] init]; + frame.index = iterIndex; + frame.duration = [self sd_frameDurationWithIterator:iter]; + frame.width = iter.width; + frame.height = iter.height; + frame.hasAlpha = iter.has_alpha; + frame.dispose = iter.dispose_method; + frame.blend = iter.blend_method; + frame.offsetX = iter.x_offset; + frame.offsetY = canvasHeight - iter.y_offset - iter.height; + + BOOL sizeEqualsToCanvas = (iter.width == canvasWidth && iter.height == canvasHeight); + BOOL offsetIsZero = (iter.x_offset == 0 && iter.y_offset == 0); + frame.isFullSize = (sizeEqualsToCanvas && offsetIsZero); + + if ((!frame.blend || !frame.hasAlpha) && frame.isFullSize) { + lastBlendIndex = iterIndex; + frame.blendFromIndex = iterIndex; + } else { + if (frame.dispose && frame.isFullSize) { + frame.blendFromIndex = lastBlendIndex; + lastBlendIndex = iterIndex + 1; + } else { + frame.blendFromIndex = lastBlendIndex; + } + } + iterIndex++; + [frames addObject:frame]; + } while (WebPDemuxNextFrame(&iter)); + WebPDemuxReleaseIterator(&iter); + + if (frames.count != frameCount) { + return NO; + } + _frames = [frames copy]; + _hasAnimation = hasAnimation; + _hasAlpha = hasAlpha; + _canvasWidth = canvasWidth; + _canvasHeight = canvasHeight; + _frameCount = frameCount; + _loopCount = loopCount; + + return YES; +} + +- (NSData *)animatedImageData +{ + return _imageData; +} + +- (NSUInteger)animatedImageLoopCount { + return _loopCount; +} + +- (NSUInteger)animatedImageFrameCount { + return _frameCount; +} + +- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { + if (index >= _frameCount) { + return 0; + } + return _frames[index].duration; +} + +- (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { + UIImage *image; + if (index >= _frameCount) { + return nil; + } + LOCK({ + image = [self safeAnimatedImageFrameAtIndex:index]; + }); + return image; +} + +- (UIImage *)safeAnimatedImageFrameAtIndex:(NSUInteger)index { + if (!_canvas) { + CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; + bitmapInfo |= _hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; + CGContextRef canvas = CGBitmapContextCreate(NULL, _canvasWidth, _canvasHeight, 8, 0, [SDWebImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo); + if (!canvas) { + return nil; + } + _canvas = canvas; + } + + SDWebPCoderFrame *frame = _frames[index]; + UIImage *image; + WebPIterator iter; + if (_currentBlendIndex + 1 == index) { + // If current blend index is equal to request index, normal serial process + _currentBlendIndex = index; + // libwebp's index start with 1 + if (!WebPDemuxGetFrame(_demux, (int)(index + 1), &iter)) { + WebPDemuxReleaseIterator(&iter); + return nil; + } + image = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter]; + } else { + // Else, this can happen when one image set to different imageViews or one loop end. So we should clear the shared cavans. + if (_currentBlendIndex != NSNotFound) { + CGContextClearRect(_canvas, CGRectMake(0, 0, _canvasWidth, _canvasHeight)); + } + _currentBlendIndex = index; + + // Then, loop from the blend from index, draw each of previous frames on the canvas. + // We use do while loop to call `WebPDemuxNextFrame`(fast), only (startIndex == endIndex) need to create image instance + size_t startIndex = frame.blendFromIndex; + size_t endIndex = frame.index; + if (!WebPDemuxGetFrame(_demux, (int)(startIndex + 1), &iter)) { + WebPDemuxReleaseIterator(&iter); + return nil; + } + do { + @autoreleasepool { + if ((size_t)iter.frame_num == endIndex) { + [self sd_blendWebpImageWithCanvas:_canvas iterator:iter]; + } else { + image = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter]; + } + } + } while ((size_t)iter.frame_num < (endIndex + 1) && WebPDemuxNextFrame(&iter)); + } + + WebPDemuxReleaseIterator(&iter); + return image; +} + @end #endif + diff --git a/SDWebImage/UIImage+ForceDecode.m b/SDWebImage/UIImage+ForceDecode.m index 27be405b..3edc796a 100644 --- a/SDWebImage/UIImage+ForceDecode.m +++ b/SDWebImage/UIImage+ForceDecode.m @@ -7,7 +7,7 @@ */ #import "UIImage+ForceDecode.h" -#import "SDWebImageCodersManager.h" +#import "SDWebImageCoderHelper.h" @implementation UIImage (ForceDecode) @@ -15,16 +15,14 @@ if (!image) { return nil; } - NSData *tempData; - return [[SDWebImageCodersManager sharedManager] decompressedImageWithImage:image data:&tempData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}]; + return [SDWebImageCoderHelper decodedImageWithImage:image]; } + (UIImage *)sd_decodedAndScaledDownImageWithImage:(UIImage *)image { if (!image) { return nil; } - NSData *tempData; - return [[SDWebImageCodersManager sharedManager] decompressedImageWithImage:image data:&tempData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(YES)}]; + return [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; } @end diff --git a/SDWebImage/UIImage+GIF.m b/SDWebImage/UIImage+GIF.m index 0af2ba84..74381eff 100644 --- a/SDWebImage/UIImage+GIF.m +++ b/SDWebImage/UIImage+GIF.m @@ -16,7 +16,7 @@ if (!data) { return nil; } - return [[SDWebImageGIFCoder sharedCoder] decodedImageWithData:data]; + return [[SDWebImageGIFCoder sharedCoder] decodedImageWithData:data options:nil]; } @end diff --git a/SDWebImage/UIImage+MultiFormat.m b/SDWebImage/UIImage+MultiFormat.m index 7007c45b..f221e0f1 100644 --- a/SDWebImage/UIImage+MultiFormat.m +++ b/SDWebImage/UIImage+MultiFormat.m @@ -12,7 +12,7 @@ @implementation UIImage (MultiFormat) + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data { - return [[SDWebImageCodersManager sharedManager] decodedImageWithData:data]; + return [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:nil]; } - (nullable NSData *)sd_imageData { @@ -22,7 +22,7 @@ - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat { NSData *imageData = nil; if (self) { - imageData = [[SDWebImageCodersManager sharedManager] encodedDataWithImage:self format:imageFormat]; + imageData = [[SDWebImageCodersManager sharedManager] encodedDataWithImage:self format:imageFormat options:nil]; } return imageData; } diff --git a/SDWebImage/UIImage+WebP.m b/SDWebImage/UIImage+WebP.m index 8329d0d4..45f86700 100644 --- a/SDWebImage/UIImage+WebP.m +++ b/SDWebImage/UIImage+WebP.m @@ -17,7 +17,7 @@ if (!data) { return nil; } - return [[SDWebImageWebPCoder sharedCoder] decodedImageWithData:data]; + return [[SDWebImageWebPCoder sharedCoder] decodedImageWithData:data options:nil]; } @end diff --git a/Tests/Tests/SDWebImageDecoderTests.m b/Tests/Tests/SDWebImageDecoderTests.m index 8ccec289..5fae2909 100644 --- a/Tests/Tests/SDWebImageDecoderTests.m +++ b/Tests/Tests/SDWebImageDecoderTests.m @@ -135,7 +135,7 @@ expect([coder canDecodeFromData:inputImageData]).to.beTruthy(); // 2 - decode from NSData to UIImage and check it - UIImage *inputImage = [coder decodedImageWithData:inputImageData]; + UIImage *inputImage = [coder decodedImageWithData:inputImageData options:nil]; expect(inputImage).toNot.beNil(); if (isAnimated) { @@ -159,7 +159,7 @@ // 4 - encode from UIImage to NSData using the inputImageFormat and check it NSData *outputImageData = [coder encodedDataWithImage:inputImage format:inputImageFormat]; expect(outputImageData).toNot.beNil(); - UIImage *outputImage = [coder decodedImageWithData:outputImageData]; + UIImage *outputImage = [coder decodedImageWithData:outputImageData options:nil]; expect(outputImage.size).to.equal(inputImage.size); expect(outputImage.scale).to.equal(inputImage.scale); expect(outputImage.images.count).to.equal(inputImage.images.count); diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index 8221d9c9..dfff3559 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -379,11 +379,6 @@ if (![data1 isEqualToData:data2]) { XCTFail(@"The image data is not equal to cutom decoder, check -[SDWebImageTestDecoder decodedImageWithData:]"); } - NSString *str1 = @"TestDecompress"; - NSString *str2 = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - if (![str1 isEqualToString:str2]) { - XCTFail(@"The image data is not modified by the custom decoder, check -[SDWebImageTestDecoder decompressedImageWithImage:data:options:]"); - } [[SDWebImageCodersManager sharedManager] removeCoder:testDecoder]; [expectation fulfill]; }]; diff --git a/Tests/Tests/SDWebImageTestDecoder.h b/Tests/Tests/SDWebImageTestDecoder.h index 29ea5644..eefb743f 100644 --- a/Tests/Tests/SDWebImageTestDecoder.h +++ b/Tests/Tests/SDWebImageTestDecoder.h @@ -10,6 +10,6 @@ #import #import -@interface SDWebImageTestDecoder : NSObject +@interface SDWebImageTestDecoder : NSObject @end diff --git a/Tests/Tests/SDWebImageTestDecoder.m b/Tests/Tests/SDWebImageTestDecoder.m index c94d7ffe..4cc494b3 100644 --- a/Tests/Tests/SDWebImageTestDecoder.m +++ b/Tests/Tests/SDWebImageTestDecoder.m @@ -19,29 +19,31 @@ return YES; } -- (UIImage *)decodedImageWithData:(NSData *)data { +- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"jpg"]; UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; return image; } +- (instancetype)initIncrementally +{ + self = [super init]; + if (self) { + } + return self; +} + - (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"gif"]; UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; return image; } -- (UIImage *)decompressedImageWithImage:(UIImage *)image - data:(NSData *__autoreleasing _Nullable *)data - options:(nullable NSDictionary*)optionsDict { - NSString *testString = @"TestDecompress"; - NSData *testData = [testString dataUsingEncoding:NSUTF8StringEncoding]; - *data = testData; - - return image; +- (BOOL)canIncrementallyDecodeFromData:(nullable NSData *)data { + return YES; } -- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format { +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDWebImageCoderOptions *)options { NSString *testString = @"TestEncode"; NSData *data = [testString dataUsingEncoding:NSUTF8StringEncoding]; return data; diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index c425cb04..ece0791a 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -44,6 +44,9 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #endif +#import +#import +#import #import #import #import From f94dd00c52ef266ec29da7d91c93e8a8d8856789 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 24 Jan 2018 00:44:44 +0800 Subject: [PATCH 063/361] Use the context arg to pass the SDAnimatedImage class to create the instance by image cache and downloader. Also enhance view category to support firstFrameOnly, scaleFactor and preload --- SDWebImage/SDAnimatedImage.h | 21 ++++- SDWebImage/SDAnimatedImage.m | 90 +++++++++++++++++----- SDWebImage/SDAnimatedImageView+WebCache.m | 6 +- SDWebImage/SDAnimatedImageView.h | 7 +- SDWebImage/SDAnimatedImageView.m | 4 +- SDWebImage/SDImageCache.h | 8 ++ SDWebImage/SDImageCache.m | 43 +++++++++-- SDWebImage/SDWebImageCoder.h | 15 +--- SDWebImage/SDWebImageCoder.m | 2 +- SDWebImage/SDWebImageCoderHelper.m | 4 +- SDWebImage/SDWebImageCompat.h | 1 + SDWebImage/SDWebImageCompat.m | 70 +++++++++-------- SDWebImage/SDWebImageDefine.h | 7 ++ SDWebImage/SDWebImageDefine.m | 1 + SDWebImage/SDWebImageDownloader.h | 10 +++ SDWebImage/SDWebImageDownloaderOperation.m | 30 +++++++- SDWebImage/SDWebImageGIFCoder.m | 22 +++--- SDWebImage/SDWebImageImageIOCoder.m | 5 ++ SDWebImage/SDWebImageManager.h | 12 +++ SDWebImage/SDWebImageManager.m | 8 +- SDWebImage/SDWebImageWebPCoder.m | 23 +++--- SDWebImage/UIImage+GIF.h | 16 +++- SDWebImage/UIImage+GIF.m | 9 ++- SDWebImage/UIImage+MultiFormat.h | 22 +++++- SDWebImage/UIImage+MultiFormat.m | 20 +++-- SDWebImage/UIImage+WebP.h | 16 ++++ SDWebImage/UIImage+WebP.m | 7 +- Tests/Tests/SDWebImageDecoderTests.m | 2 +- 28 files changed, 365 insertions(+), 116 deletions(-) diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h index 141d5462..47bee11c 100644 --- a/SDWebImage/SDAnimatedImage.h +++ b/SDWebImage/SDAnimatedImage.h @@ -27,7 +27,7 @@ - (NSUInteger)animatedImageLoopCount; /** Returns the frame image from a specified index. - This method may be called on background thread. And the index maybe randomly if one image was set to different imageViews, keep it re-entrant. + @note The index maybe randomly if one image was set to different imageViews, keep it re-entrant. (It's not recommend to store the images into array because it's memory consuming) @param index Frame index (zero based). @return Frame's image @@ -35,12 +35,22 @@ - (nullable UIImage *)animatedImageFrameAtIndex:(NSUInteger)index; /** Returns the frames's duration from a specified index. + @note The index maybe randomly if one image was set to different imageViews, keep it re-entrant. (It's recommend to store the durations into array because it's not memory-consuming) @param index Frame index (zero based). @return Frame's duration */ - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index; +@optional +/** + Preload all frame image to memory. Then 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. + */ +- (void)preloadAllFrames; + @end @interface SDAnimatedImage : UIImage @@ -63,4 +73,13 @@ */ @property (nonatomic, copy, readonly, nullable) NSData *animatedImageData; +/** + Preload all frame image to memory. Then 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. + @note Once preload the frames into memory, there is no huge differenec on performance between UIImage's `animatedImageWithImages:duration:` for UIKit. But UIImage's animation have some issue such like blanking or frame resetting. It's recommend to use only if need. + */ +- (void)preloadAllFrames; + @end diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index 668b5a9a..f69e6380 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -11,6 +11,7 @@ #import "UIImage+WebCache.h" #import "SDWebImageCoder.h" #import "SDWebImageCodersManager.h" +#import "SDWebImageFrame.h" static CGFloat SDImageScaleFromPath(NSString *string) { if (string.length == 0 || [string hasSuffix:@"/"]) return 1; @@ -32,8 +33,11 @@ static CGFloat SDImageScaleFromPath(NSString *string) { @property (nonatomic, strong) id coder; @property (nonatomic, assign, readwrite) NSUInteger animatedImageLoopCount; @property (nonatomic, assign, readwrite) NSUInteger animatedImageFrameCount; +@property (nonatomic, copy, readwrite) NSData *animatedImageData; @property (nonatomic, assign, readwrite) SDImageFormat animatedImageFormat; -@property (nonatomic, assign) BOOL animatedImageLoopCountCheck; +@property (atomic, copy) NSArray *preloadAnimatedImageFrames; +@property (nonatomic, assign) BOOL animatedImageFramesPreloaded; +@property (nonatomic, assign) BOOL animatedImageLoopCountChecked; @property (nonatomic, assign) BOOL animatedImageFrameCountChecked; #if SD_MAC @@ -44,6 +48,21 @@ static CGFloat SDImageScaleFromPath(NSString *string) { @implementation SDAnimatedImage +#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)imageWithContentsOfFile:(NSString *)path { return [[self alloc] initWithContentsOfFile:path]; @@ -70,14 +89,8 @@ static CGFloat SDImageScaleFromPath(NSString *string) { if (!data || data.length == 0) { return nil; } - if (scale <= 0) { -#if SD_WATCH - scale = [WKInterfaceDevice currentDevice].screenScale; -#elif SD_UIKIT - scale = [UIScreen mainScreen].scale; -#endif - } - for (idcoder in [SDWebImageCodersManager sharedInstance].coders) { + data = [data copy]; // avoid mutable data + for (idcoder in [SDWebImageCodersManager sharedManager].coders) { if ([coder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { if ([coder canDecodeFromData:data]) { id animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data]; @@ -98,19 +111,44 @@ static CGFloat SDImageScaleFromPath(NSString *string) { if (!image) { return nil; } + if (scale <= 0) { + scale = 1; + } #if SD_MAC - self = [super initWithCGImage:image.CGImage size:NSZeroSize]; + self = [super initWithCGImage:image.CGImage scale:scale]; #else self = [super initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; #endif - if (!self) { - return nil; + if (self) { +#if SD_MAC + _scale = scale; +#endif + _animatedImageData = data; + SDImageFormat format = [NSData sd_imageFormatForImageData:data]; + _animatedImageFormat = format; } - SDImageFormat format = [NSData sd_imageFormatForImageData:data]; - self.animatedImageFormat = format; return self; } +#pragma mark - Preload +- (void)preloadAllFrames { + if (!self.animatedImageFramesPreloaded) { + NSMutableArray *frames = [NSMutableArray arrayWithCapacity:self.animatedImageFrameCount]; + for (size_t i = 0; i < self.animatedImageFrameCount; i++) { + UIImage *image = [self animatedImageFrameAtIndex:i]; + NSTimeInterval duration = [self animatedImageDurationAtIndex:i]; + 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 + } +} + #pragma mark - NSSecureCoding - (instancetype)initWithCoder:(NSCoder *)aDecoder { NSNumber *scale = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(scale))]; @@ -137,8 +175,8 @@ static CGFloat SDImageScaleFromPath(NSString *string) { #pragma mark - SDAnimatedImage - (NSUInteger)animatedImageLoopCount { - if (!self.animatedImageLoopCountCheck) { - self.animatedImageLoopCountCheck = YES; + if (!self.animatedImageLoopCountChecked) { + self.animatedImageLoopCountChecked = YES; _animatedImageLoopCount = [self.coder animatedImageLoopCount]; } return _animatedImageLoopCount; @@ -153,15 +191,25 @@ static CGFloat SDImageScaleFromPath(NSString *string) { } - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { + if (index >= self.animatedImageFrameCount) { + return nil; + } + if (self.animatedImageFramesPreloaded) { + SDWebImageFrame *frame = [self.preloadAnimatedImageFrames objectAtIndex:index]; + return frame.image; + } return [self.coder animatedImageFrameAtIndex:index]; } -- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { +- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { + if (index >= self.animatedImageFrameCount) { + return 0; + } + if (self.animatedImageFramesPreloaded) { + SDWebImageFrame *frame = [self.preloadAnimatedImageFrames objectAtIndex:index]; + return frame.duration; + } return [self.coder animatedImageDurationAtIndex:index]; } -- (NSData *)animatedImageData { - return self.coder.animatedImageData; -} - @end diff --git a/SDWebImage/SDAnimatedImageView+WebCache.m b/SDWebImage/SDAnimatedImageView+WebCache.m index a4a8c9db..4ec46e7d 100644 --- a/SDWebImage/SDAnimatedImageView+WebCache.m +++ b/SDWebImage/SDAnimatedImageView+WebCache.m @@ -11,6 +11,7 @@ #if SD_UIKIT || SD_MAC #import "UIView+WebCache.h" +#import "SDAnimatedImage.h" @implementation SDAnimatedImageView (WebCache) @@ -43,13 +44,16 @@ options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { + Class animatedImageClass = [SDAnimatedImage class]; + SDWebImageContext *context = @{SDWebImageContextAnimatedImageClass : animatedImageClass}; [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options operationKey:nil setImageBlock:nil progress:progressBlock - completed:completedBlock]; + completed:completedBlock + context:context]; } @end diff --git a/SDWebImage/SDAnimatedImageView.h b/SDWebImage/SDAnimatedImageView.h index b31d5806..9c30b394 100644 --- a/SDWebImage/SDAnimatedImageView.h +++ b/SDWebImage/SDAnimatedImageView.h @@ -31,7 +31,7 @@ */ @property (nonatomic, assign, readonly) NSUInteger currentLoopCount; /** - YES to choose `animationRepeatCount` property instead of image's loop count for animtion loop count. Default is NO. + YES to choose `animationRepeatCount` property instead of image's loop count for animation loop count. Default is NO. */ @property (nonatomic, assign) BOOL shouldCustomLoopCount; /** @@ -40,6 +40,11 @@ This class override UIImageView's `animationRepeatCount` property on iOS, use this property as well. */ @property (nonatomic, assign) NSInteger animationRepeatCount; +/** + Returns a Boolean value indicating whether the animation is running. + This class override UIImageView's `animating` property on iOS, use this property as well. + */ +@property (nonatomic, readonly, getter=isAnimating) BOOL animating; /** Provide a max buffer size by bytes. This is used to adjust frame buffer count and can be useful when the decoding cost is expensive (such as Animated WebP software decoding). Default is 0. `0` means automatically adjust by calculating current memory usage. diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index 35f1b500..f50e5431 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -19,7 +19,7 @@ static CVReturn renderCallback(CVDisplayLinkRef displayLink, const CVTimeStamp * #endif static NSUInteger SDDeviceTotalMemory() { - return [[NSProcessInfo processInfo] physicalMemory]; + return (NSUInteger)[[NSProcessInfo processInfo] physicalMemory]; } static NSUInteger SDDeviceFreeMemory() { @@ -226,6 +226,7 @@ dispatch_semaphore_signal(self->_lock); self.bufferMiss = NO; self.shouldAnimate = NO; self.maxBufferCount = 0; + self.layer.contentsScale = 1; [_frameBuffer removeAllObjects]; _frameBuffer = nil; [_fetchQueue cancelAllOperations]; @@ -276,6 +277,7 @@ dispatch_semaphore_signal(self->_lock); [self startAnimating]; } + self.layer.contentsScale = image.scale; [self.layer setNeedsDisplay]; } } diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 07dfee44..ea8b3a1a 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -40,6 +40,14 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { * Use this flag to transform them anyway. */ SDImageCacheTransformAnimatedImage = 1 << 2, + /** + * By default, we decode the animated image. This flag can force decode the first frame only and produece the static image. + */ + SDImageCacheDecodeFirstFrameOnly = 1 << 3, + /** + * By default, for `SDAnimatedImage`, we decode the animated image frame during rendering to reduce memory usage. This flag actually trigger `preloadAllAnimatedImageFrames = YES` after image load from disk cache + */ + SDImageCachePreloadAllFrames = 1 << 4 }; typedef void(^SDCacheQueryCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType); diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 6d7c15a5..8c069bec 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -9,9 +9,11 @@ #import "SDImageCache.h" #import #import "NSImage+Additions.h" +#import "UIImage+WebCache.h" #import "SDWebImageCodersManager.h" #import "SDWebImageTransformer.h" #import "SDWebImageCoderHelper.h" +#import "SDAnimatedImage.h" #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); #define UNLOCK(lock) dispatch_semaphore_signal(lock); @@ -476,11 +478,42 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } - (nullable UIImage *)diskImageForKey:(nullable NSString *)key data:(nullable NSData *)data { + return [self diskImageForKey:key data:data options:0 context:nil]; +} + +- (nullable UIImage *)diskImageForKey:(nullable NSString *)key data:(nullable NSData *)data options:(SDImageCacheOptions)options context:(SDWebImageContext *)context { if (data) { - UIImage *image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:nil]; - image = [self scaledImageForKey:key image:image]; - if (self.config.shouldDecompressImages) { - image = [SDWebImageCoderHelper decodedImageWithImage:image]; + UIImage *image; + BOOL decodeFirstFrame = options & SDImageCacheDecodeFirstFrameOnly; + if (!decodeFirstFrame) { + // check whether we should use `SDAnimatedImage` + if ([context valueForKey:SDWebImageContextAnimatedImageClass]) { + Class animatedImageClass = [context valueForKey:SDWebImageContextAnimatedImageClass]; + if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { + CGFloat scale = SDImageScaleForKey(key); + image = [[animatedImageClass alloc] initWithData:data scale:scale]; + if (options & SDImageCachePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { + [((id)image) preloadAllFrames]; + } + } + } + } + if (!image) { + image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame)}]; + image = [self scaledImageForKey:key image:image]; + } + BOOL shouldDecode = YES; + if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { + // `SDAnimatedImage` do not decode + shouldDecode = NO; + } else if (image.sd_isAnimated) { + // animated image do not decode + shouldDecode = NO; + } + if (shouldDecode) { + if (self.config.shouldDecompressImages) { + image = [SDWebImageCoderHelper decodedImageWithImage:image]; + } } return image; } else { @@ -542,7 +575,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { cacheKey = SDTransformedKeyForKey(key, transformerKey); } // decode image data only if in-memory cache missed - diskImage = [self diskImageForKey:cacheKey data:diskData]; + diskImage = [self diskImageForKey:cacheKey data:diskData options:options context:context]; if (diskImage && self.config.shouldCacheImagesInMemory) { NSUInteger cost = SDCacheCostForImage(diskImage); [self.memCache setObject:diskImage forKey:cacheKey cost:cost]; diff --git a/SDWebImage/SDWebImageCoder.h b/SDWebImage/SDWebImageCoder.h index 2345df63..ee6fdd34 100644 --- a/SDWebImage/SDWebImageCoder.h +++ b/SDWebImage/SDWebImageCoder.h @@ -19,9 +19,9 @@ typedef NSDictionary SDWebImageCoderOptions; */ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderDecodeFirstFrameOnly; /** - A double value between 0.0-1.0 indicating the encode quality to produce the image data. If not provide, use 1.0. (NSNumber) + A double value between 0.0-1.0 indicating the encode compression quality to produce the image data. If not provide, use 1.0. (NSNumber) */ -FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeQuality; +FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeCompressionQuality; /** This is the image coder protocol to provide custom image decoding/encoding. @@ -44,7 +44,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeQual Decode the image data to image. @param data The image data to be decoded - @param optionsDict A dictionary containing any decoding options. Pass {SDWebImageCoderDecodeFirstFrameOnlyKey: @(YES)} to decode the first frame only. + @param options A dictionary containing any decoding options. Pass @{SDWebImageCoderDecodeFirstFrameOnly: @(YES)} to decode the first frame only. @return The decoded image from data */ - (nullable UIImage *)decodedImageWithData:(nullable NSData *)data @@ -65,6 +65,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeQual @param image The image to be encoded @param format The image format to encode, you should note `SDImageFormatUndefined` format is also possible + @param options A dictionary containing any encoding options. Pass @{SDWebImageCoderEncodeCompressionQuality: @(1)} to specify compression quality. @return The encoded image data */ - (nullable NSData *)encodedDataWithImage:(nullable UIImage *)image @@ -121,12 +122,4 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeQual */ - (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data; -/** - Return the current animated image data. This is used for image instance archive or image information retrieval - You can return back the desired data(may be not the same instance provide for init method, but have the equal data) - - @return The animated image data - */ -- (nullable NSData *)animatedImageData; - @end diff --git a/SDWebImage/SDWebImageCoder.m b/SDWebImage/SDWebImageCoder.m index 4f66a48c..8c8ec4b4 100644 --- a/SDWebImage/SDWebImageCoder.m +++ b/SDWebImage/SDWebImageCoder.m @@ -9,4 +9,4 @@ #import "SDWebImageCoder.h" SDWebImageCoderOption const SDWebImageCoderDecodeFirstFrameOnly = @"decodeFirstFrameOnly"; -SDWebImageCoderOption const SDWebImageCoderEncodeQuality = @"encodeQuality"; +SDWebImageCoderOption const SDWebImageCoderEncodeCompressionQuality = @"compressionQuality"; diff --git a/SDWebImage/SDWebImageCoderHelper.m b/SDWebImage/SDWebImageCoderHelper.m index 71620cc2..901fc39a 100644 --- a/SDWebImage/SDWebImageCoderHelper.m +++ b/SDWebImage/SDWebImageCoderHelper.m @@ -23,7 +23,7 @@ static const size_t kBitsPerComponent = 8; * Suggested value for iPad2 and iPhone 4: 120. * Suggested value for iPhone 3G and iPod 2 and earlier devices: 30. */ -static const CGFloat kDestImageSizeMB = 120.f; +static const CGFloat kDestImageSizeMB = 60.f; /* * Defines the maximum size in MB of a tile used to decode image when the flag `SDWebImageScaleDownLargeImages` is set @@ -31,7 +31,7 @@ static const CGFloat kDestImageSizeMB = 120.f; * Suggested value for iPad2 and iPhone 4: 40. * Suggested value for iPhone 3G and iPod 2 and earlier devices: 10. */ -static const CGFloat kSourceImageTileSizeMB = 40.f; +static const CGFloat kSourceImageTileSizeMB = 20.f; static const CGFloat kBytesPerMB = 1024.0f * 1024.0f; static const CGFloat kPixelsPerMB = kBytesPerMB / kBytesPerPixel; diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index 87142799..50ef17c2 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -83,6 +83,7 @@ #define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type #endif +FOUNDATION_EXPORT CGFloat SDImageScaleForKey(NSString * _Nullable key); FOUNDATION_EXPORT UIImage * _Nullable SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image); FOUNDATION_EXPORT NSString *const _Nonnull SDWebImageErrorDomain; diff --git a/SDWebImage/SDWebImageCompat.m b/SDWebImage/SDWebImageCompat.m index 35dedc42..e54c274d 100644 --- a/SDWebImage/SDWebImageCompat.m +++ b/SDWebImage/SDWebImageCompat.m @@ -18,6 +18,34 @@ #error SDWebImage need ARC for dispatch object #endif +inline CGFloat SDImageScaleForKey(NSString * _Nullable key) { + CGFloat scale = 1; + if (!key) { + return scale; + } +#if SD_WATCH + if ([[WKInterfaceDevice currentDevice] respondsToSelector:@selector(screenScale)]) +#elif SD_UIKIT + if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) +#elif SD_MAC + if ([[NSScreen mainScreen] respondsToSelector:@selector(backingScaleFactor)]) +#endif + { + if (key.length >= 8) { + NSRange range = [key rangeOfString:@"@2x."]; + if (range.location != NSNotFound) { + scale = 2.0; + } + + range = [key rangeOfString:@"@3x."]; + if (range.location != NSNotFound) { + scale = 3.0; + } + } + } + return scale; +} + inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) { if (!image) { return nil; @@ -36,40 +64,18 @@ inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullabl animatedImage.sd_imageLoopCount = image.sd_imageLoopCount; } return animatedImage; - } else { -#endif -#if SD_WATCH - if ([[WKInterfaceDevice currentDevice] respondsToSelector:@selector(screenScale)]) { -#elif SD_UIKIT - if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) { -#elif SD_MAC - if ([[NSScreen mainScreen] respondsToSelector:@selector(backingScaleFactor)]) { -#endif - CGFloat scale = 1; - if (key.length >= 8) { - NSRange range = [key rangeOfString:@"@2x."]; - if (range.location != NSNotFound) { - scale = 2.0; - } - - range = [key rangeOfString:@"@3x."]; - if (range.location != NSNotFound) { - scale = 3.0; - } - } - if (scale > 1) { -#if SD_UIKIT || SD_WATCH - UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; -#else - UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale]; -#endif - image = scaledImage; - } - } - return image; -#if SD_UIKIT || SD_WATCH } #endif + CGFloat scale = SDImageScaleForKey(key); + if (scale > 1) { +#if SD_UIKIT || SD_WATCH + UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; +#else + UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale]; +#endif + image = scaledImage; + } + return image; } NSString *const SDWebImageErrorDomain = @"SDWebImageErrorDomain"; diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index 4437d578..23a4086c 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -16,6 +16,7 @@ typedef NSDictionary SDWebImageContext; A Dispatch group to maintain setImageBlock and completionBlock. This is used for custom setImageBlock advanced usage, such like perform background task but need to guarantee the completion block is called after setImageBlock. (dispatch_group_t) */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextSetImageGroup; + /** A SDWebImageManager instance to control the image download and cache process using in UIImageView+WebCache category and likes. If not provided, use the shared manager (SDWebImageManager) */ @@ -25,3 +26,9 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustom A id instance which conforms SDWebImageTransformer protocol. It's used for image transform after the image load finished and store the transformed image to cache. If you provide one, it will ignore the `transformer` in manager and use provided one instead. (id) */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustomTransformer; + +/** + A Class object which the instance is a `UIImage/NSImage` subclass and adopt `SDAnimatedImage` protocol. And call `initWithData:scale:` to create the instance. If the instance create failed, fallback to normal `UIImage/NSImage`. + This can be used to improve animated images rendering performance (especially memory usage on big animated images) with `SDAnimatedImageView` (Class). + */ +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextAnimatedImageClass; diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m index ae88e07f..41be5f9d 100644 --- a/SDWebImage/SDWebImageDefine.m +++ b/SDWebImage/SDWebImageDefine.m @@ -11,3 +11,4 @@ SDWebImageContextOption const SDWebImageContextSetImageGroup = @"setImageGroup"; SDWebImageContextOption const SDWebImageContextCustomManager = @"customManager"; SDWebImageContextOption const SDWebImageContextCustomTransformer = @"customTransformer"; +SDWebImageContextOption const SDWebImageContextAnimatedImageClass = @"animatedImageClass"; diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index a2cbb2a4..7c5efe88 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -61,6 +61,16 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { * Scale down the image */ SDWebImageDownloaderScaleDownLargeImages = 1 << 8, + + /** + * By default, we decode the animated image. This flag can force decode the first frame only and produece the static image. + */ + SDWebImageDownloaderDecodeFirstFrameOnly = 1 << 9, + + /** + * By default, for `SDAnimatedImage`, we decode the animated image frame during rendering to reduce memory usage. This flag actually trigger `preloadAllAnimatedImageFrames = YES` after image load from network + */ + SDWebImageDownloaderPreloadAllFrames = 1 << 10 }; typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index bb6baf14..be454c43 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -9,8 +9,10 @@ #import "SDWebImageDownloaderOperation.h" #import "SDWebImageManager.h" #import "NSImage+Additions.h" +#import "UIImage+WebCache.h" #import "SDWebImageCodersManager.h" #import "SDWebImageCoderHelper.h" +#import "SDAnimatedImage.h" #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); #define UNLOCK(lock) dispatch_semaphore_signal(lock); @@ -428,13 +430,33 @@ didReceiveResponse:(NSURLResponse *)response } else { // decode the image in coder queue dispatch_async(self.coderQueue, ^{ - UIImage *image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:nil]; + BOOL decodeFirstFrame = self.options & SDWebImageDownloaderDecodeFirstFrameOnly; NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; - image = [self scaledImageForKey:key image:image]; + UIImage *image; + if (!decodeFirstFrame) { + // check whether we should use `SDAnimatedImage` + if ([self.context valueForKey:SDWebImageContextAnimatedImageClass]) { + Class animatedImageClass = [self.context valueForKey:SDWebImageContextAnimatedImageClass]; + if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { + CGFloat scale = SDImageScaleForKey(key); + image = [[animatedImageClass alloc] initWithData:imageData scale:scale]; + if (self.options & SDWebImageDownloaderPreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { + [((id)image) preloadAllFrames]; + } + } + } + } + if (!image) { + image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame)}]; + image = [self scaledImageForKey:key image:image]; + } BOOL shouldDecode = YES; - // Do not force decoding animated GIFs and WebPs - if (image.images) { + if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { + // `SDAnimatedImage` do not decode + shouldDecode = NO; + } else if (image.sd_isAnimated) { + // animated image do not decode shouldDecode = NO; } if (shouldDecode) { diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index 3ff30d6f..17403262 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -70,7 +70,7 @@ return ([NSData sd_imageFormatForImageData:data] == SDImageFormatGIF); } -- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable NSDictionary *)optionsDict { +- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { if (!data) { return nil; } @@ -90,7 +90,7 @@ UIImage *animatedImage; - BOOL decodeFirstFrame = [optionsDict[SDWebImageCoderDecodeFirstFrameOnly] boolValue]; + BOOL decodeFirstFrame = [options[SDWebImageCoderDecodeFirstFrameOnly] boolValue]; if (decodeFirstFrame || count <= 1) { animatedImage = [[UIImage alloc] initWithData:data]; } else { @@ -191,14 +191,21 @@ // Handle failure. return nil; } + NSMutableDictionary *properties = [NSMutableDictionary dictionary]; + double compressionQuality = 1; + if ([options valueForKey:SDWebImageCoderEncodeCompressionQuality]) { + compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue]; + } + [properties setValue:@(compressionQuality) forKey:(__bridge_transfer NSString *)kCGImageDestinationLossyCompressionQuality]; if (frames.count == 0) { // for static single GIF images - CGImageDestinationAddImage(imageDestination, image.CGImage, nil); + CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); } else { // for animated GIF images NSUInteger loopCount = image.sd_imageLoopCount; - NSDictionary *gifProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary: @{(__bridge_transfer NSString *)kCGImagePropertyGIFLoopCount : @(loopCount)}}; - CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)gifProperties); + NSDictionary *gifProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFLoopCount : @(loopCount)}; + [properties setValue:gifProperties forKey:(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary]; + CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)properties); for (size_t i = 0; i < frames.count; i++) { SDWebImageFrame *frame = frames[i]; @@ -268,11 +275,6 @@ return YES; } -- (NSData *)animatedImageData -{ - return _imageData; -} - - (NSUInteger)animatedImageLoopCount { return _loopCount; diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index efc98c8f..b6e2ea5b 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -229,6 +229,11 @@ NSInteger exifOrientation = [SDWebImageCoderHelper exifOrientationFromImageOrientation:image.imageOrientation]; [properties setValue:@(exifOrientation) forKey:(__bridge_transfer NSString *)kCGImagePropertyOrientation]; #endif + double compressionQuality = 1; + if ([options valueForKey:SDWebImageCoderEncodeCompressionQuality]) { + compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue]; + } + [properties setValue:@(compressionQuality) forKey:(__bridge_transfer NSString *)kCGImageDestinationLossyCompressionQuality]; // Add your image to the destination. CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index d28ad8f7..f0206e99 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -112,10 +112,22 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { * By default, when the cache missed, the image is download from the network. This flag can prevent network to load from cache only. */ SDWebImageFromCacheOnly = 1 << 15, + /** * By default, when you use `SDWebImageTransition` to do some view transition after the image load finished, this transition is only applied for image download from the network. This mask can force to apply view transition for memory and disk cache as well. */ SDWebImageForceTransition = 1 << 16, + + /** + * By default, we decode the animated image. This flag can force decode the first frame only and produece the static image. + */ + SDWebImageDecodeFirstFrameOnly = 1 << 17, + + /** + * By default, for `SDAnimatedImage`, we decode the animated image frame during rendering to reduce memory usage. However, you can specify to preload all frames into memory to reduce CPU usage when the animated image is shared by lots of imageViews. + * This will actually trigger `preloadAllAnimatedImageFrames` in the background queue(Disk Cache & Download only). + */ + SDWebImagePreloadAllFrames = 1 << 18 }; typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL); diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index f92ed841..2bc16e51 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -8,6 +8,8 @@ #import "SDWebImageManager.h" #import "NSImage+Additions.h" +#import "UIImage+WebCache.h" +#import "SDAnimatedImage.h" @interface SDWebImageCombinedOperation : NSObject @@ -153,6 +155,8 @@ if (options & SDWebImageQueryDataWhenInMemory) cacheOptions |= SDImageCacheQueryDataWhenInMemory; if (options & SDWebImageQueryDiskSync) cacheOptions |= SDImageCacheQueryDiskSync; if (options & SDWebImageTransformAnimatedImage) cacheOptions |= SDImageCacheTransformAnimatedImage; + if (options & SDWebImageDecodeFirstFrameOnly) cacheOptions |= SDImageCacheDecodeFirstFrameOnly; + if (options & SDWebImagePreloadAllFrames) cacheOptions |= SDImageCachePreloadAllFrames; // Image transformer id transformer; @@ -195,6 +199,8 @@ if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates; if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority; if (options & SDWebImageScaleDownLargeImages) downloaderOptions |= SDWebImageDownloaderScaleDownLargeImages; + if (options & SDWebImageDecodeFirstFrameOnly) downloaderOptions |= SDWebImageDownloaderDecodeFirstFrameOnly; + if (options & SDWebImagePreloadAllFrames) downloaderOptions |= SDWebImageDownloaderPreloadAllFrames; if (cachedImage && options & SDWebImageRefreshCached) { // force progressive off if image already cached but forced refreshing @@ -244,7 +250,7 @@ BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly); // We've done the scale process in SDWebImageDownloader with the shared manager, this is used for custom manager and avoid extra scale. - if (self != [SDWebImageManager sharedManager] && self.cacheKeyFilter && downloadedImage) { + if (self != [SDWebImageManager sharedManager] && self.cacheKeyFilter && downloadedImage && ![downloadedImage conformsToProtocol:@protocol(SDAnimatedImage)]) { downloadedImage = [self scaledImageForKey:key image:downloadedImage]; } diff --git a/SDWebImage/SDWebImageWebPCoder.m b/SDWebImage/SDWebImageWebPCoder.m index 536c3526..47af8ea2 100644 --- a/SDWebImage/SDWebImageWebPCoder.m +++ b/SDWebImage/SDWebImageWebPCoder.m @@ -96,7 +96,7 @@ dispatch_semaphore_signal(self->_lock); return ([NSData sd_imageFormatForImageData:data] == SDImageFormatWebP); } -- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable NSDictionary *)optionsDict { +- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { if (!data) { return nil; } @@ -112,7 +112,7 @@ dispatch_semaphore_signal(self->_lock); uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS); BOOL hasAnimation = flags & ANIMATION_FLAG; - BOOL decodeFirstFrame = [[optionsDict valueForKey:SDWebImageCoderDecodeFirstFrameOnly] boolValue]; + BOOL decodeFirstFrame = [[options valueForKey:SDWebImageCoderDecodeFirstFrameOnly] boolValue]; if (!hasAnimation) { // for static single webp image UIImage *staticImage = [self sd_rawWebpImageWithData:webpData]; @@ -391,10 +391,14 @@ dispatch_semaphore_signal(self->_lock); NSData *data; + double compressionQuality = 1; + if ([options valueForKey:SDWebImageCoderEncodeCompressionQuality]) { + compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue]; + } NSArray *frames = [SDWebImageCoderHelper framesFromAnimatedImage:image]; if (frames.count == 0) { // for static single webp image - data = [self sd_encodedWebpDataWithImage:image]; + data = [self sd_encodedWebpDataWithImage:image quality:compressionQuality]; } else { // for animated webp image WebPMux *mux = WebPMuxNew(); @@ -403,7 +407,7 @@ dispatch_semaphore_signal(self->_lock); } for (size_t i = 0; i < frames.count; i++) { SDWebImageFrame *currentFrame = frames[i]; - NSData *webpData = [self sd_encodedWebpDataWithImage:currentFrame.image]; + NSData *webpData = [self sd_encodedWebpDataWithImage:currentFrame.image quality:compressionQuality]; int duration = currentFrame.duration * 1000; WebPMuxFrameInfo frame = { .bitstream.bytes = webpData.bytes, .bitstream.size = webpData.length, @@ -440,7 +444,7 @@ dispatch_semaphore_signal(self->_lock); return data; } -- (nullable NSData *)sd_encodedWebpDataWithImage:(nullable UIImage *)image { +- (nullable NSData *)sd_encodedWebpDataWithImage:(nullable UIImage *)image quality:(double)quality { if (!image) { return nil; } @@ -466,8 +470,8 @@ dispatch_semaphore_signal(self->_lock); uint8_t *rgba = (uint8_t *)CFDataGetBytePtr(dataRef); uint8_t *data = NULL; - float quality = 100.0; - size_t size = WebPEncodeRGBA(rgba, (int)width, (int)height, (int)bytesPerRow, quality, &data); + float qualityFactor = quality * 100; // WebP quality is 0-100 + size_t size = WebPEncodeRGBA(rgba, (int)width, (int)height, (int)bytesPerRow, qualityFactor, &data); CFRelease(dataRef); rgba = NULL; @@ -582,11 +586,6 @@ static void FreeImageData(void *info, const void *data, size_t size) { return YES; } -- (NSData *)animatedImageData -{ - return _imageData; -} - - (NSUInteger)animatedImageLoopCount { return _loopCount; } diff --git a/SDWebImage/UIImage+GIF.h b/SDWebImage/UIImage+GIF.h index 5748b948..1062a291 100644 --- a/SDWebImage/UIImage+GIF.h +++ b/SDWebImage/UIImage+GIF.h @@ -12,9 +12,21 @@ @interface UIImage (GIF) /** - * Creates an animated UIImage from an NSData. - * For static GIF, will create an UIImage with `images` array set to nil. For animated GIF, will create an UIImage with valid `images` array. + Creates an animated UIImage from an NSData. + For Static GIF, will create an UIImage with `images` array set to nil. For Animated GIF, will create an UIImage with valid `images` array. + + @param data The GIF data + @return The created image */ + (nullable UIImage *)sd_animatedGIFWithData:(nullable NSData *)data; +/** + Creates an animated UIImage from an NSData. + + @param data The GIF data + @param firstFrameOnly Even if the image data is Animated GIF format, decode the first frame only + @return The created image + */ ++ (nullable UIImage *)sd_animatedGIFWithData:(nullable NSData *)data firstFrameOnly:(BOOL)firstFrameOnly; + @end diff --git a/SDWebImage/UIImage+GIF.m b/SDWebImage/UIImage+GIF.m index 74381eff..0698a923 100644 --- a/SDWebImage/UIImage+GIF.m +++ b/SDWebImage/UIImage+GIF.m @@ -12,11 +12,16 @@ @implementation UIImage (GIF) -+ (UIImage *)sd_animatedGIFWithData:(NSData *)data { ++ (nullable UIImage *)sd_animatedGIFWithData:(nullable NSData *)data { + return [self sd_animatedGIFWithData:data firstFrameOnly:NO]; +} + ++ (nullable UIImage *)sd_animatedGIFWithData:(nullable NSData *)data firstFrameOnly:(BOOL)firstFrameOnly { if (!data) { return nil; } - return [[SDWebImageGIFCoder sharedCoder] decodedImageWithData:data options:nil]; + SDWebImageCoderOptions *options = @{SDWebImageCoderDecodeFirstFrameOnly : @(firstFrameOnly)}; + return [[SDWebImageGIFCoder sharedCoder] decodedImageWithData:data options:options]; } @end diff --git a/SDWebImage/UIImage+MultiFormat.h b/SDWebImage/UIImage+MultiFormat.h index f316fe96..c66ae83c 100644 --- a/SDWebImage/UIImage+MultiFormat.h +++ b/SDWebImage/UIImage+MultiFormat.h @@ -10,15 +10,26 @@ #import "NSData+ImageContentType.h" @interface UIImage (MultiFormat) - +#pragma mark - Decode /** Create and decode a image with the specify image data + If the image data is animated image format, create an animated image if possible @param data The image data @return The created image */ + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data; +/** + Create and decode a image with the specify image data + + @param data The image data + @param firstFrameOnly Even if the image data is animated image format, decode the first frame only + @return The created image + */ ++ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data firstFrameOnly:(BOOL)firstFrameOnly; + +#pragma mark - Encode /** Encode the current image to the data, the image format is unspecified @@ -34,4 +45,13 @@ */ - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat; +/** + Encode the current image to data with the specify image format + + @param imageFormat The specify image format + @param compressionQuality The quality of the resulting image data. Value between 0.0-1.0. Some coders may not support compression quality. + @return The encoded data. If can't encode, return nil + */ +- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat compressionQuality:(double)compressionQuality; + @end diff --git a/SDWebImage/UIImage+MultiFormat.m b/SDWebImage/UIImage+MultiFormat.m index f221e0f1..846bd167 100644 --- a/SDWebImage/UIImage+MultiFormat.m +++ b/SDWebImage/UIImage+MultiFormat.m @@ -12,7 +12,15 @@ @implementation UIImage (MultiFormat) + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data { - return [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:nil]; + return [self sd_imageWithData:data firstFrameOnly:NO]; +} + ++ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data firstFrameOnly:(BOOL)firstFrameOnly { + if (!data) { + return nil; + } + SDWebImageCoderOptions *options = @{SDWebImageCoderDecodeFirstFrameOnly : @(firstFrameOnly)}; + return [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:options]; } - (nullable NSData *)sd_imageData { @@ -20,12 +28,12 @@ } - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat { - NSData *imageData = nil; - if (self) { - imageData = [[SDWebImageCodersManager sharedManager] encodedDataWithImage:self format:imageFormat options:nil]; - } - return imageData; + return [self sd_imageDataAsFormat:imageFormat compressionQuality:1]; } +- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat compressionQuality:(double)compressionQuality { + SDWebImageCoderOptions *options = @{SDWebImageCoderEncodeCompressionQuality : @(compressionQuality)}; + return [[SDWebImageCodersManager sharedManager] encodedDataWithImage:self format:imageFormat options:options]; +} @end diff --git a/SDWebImage/UIImage+WebP.h b/SDWebImage/UIImage+WebP.h index cd9f27b1..7f4f50d4 100644 --- a/SDWebImage/UIImage+WebP.h +++ b/SDWebImage/UIImage+WebP.h @@ -12,8 +12,24 @@ @interface UIImage (WebP) +/** + Create a image from the WebP data. + This may create animated image if the data is Animated WebP. + + @param data The WebP data + @return The created image + */ + (nullable UIImage *)sd_imageWithWebPData:(nullable NSData *)data; +/** + Create a image from the WebP data. + + @param data The WebP data + @param firstFrameOnly Even if the image data is Animated WebP format, decode the first frame only + @return The created image + */ ++ (nullable UIImage *)sd_imageWithWebPData:(nullable NSData *)data firstFrameOnly:(BOOL)firstFrameOnly; + @end #endif diff --git a/SDWebImage/UIImage+WebP.m b/SDWebImage/UIImage+WebP.m index 45f86700..db1fa6a9 100644 --- a/SDWebImage/UIImage+WebP.m +++ b/SDWebImage/UIImage+WebP.m @@ -14,10 +14,15 @@ @implementation UIImage (WebP) + (nullable UIImage *)sd_imageWithWebPData:(nullable NSData *)data { + return [self sd_imageWithWebPData:data firstFrameOnly:NO]; +} + ++ (nullable UIImage *)sd_imageWithWebPData:(nullable NSData *)data firstFrameOnly:(BOOL)firstFrameOnly { if (!data) { return nil; } - return [[SDWebImageWebPCoder sharedCoder] decodedImageWithData:data options:nil]; + SDWebImageCoderOptions *options = @{SDWebImageCoderDecodeFirstFrameOnly : @(firstFrameOnly)}; + return [[SDWebImageWebPCoder sharedCoder] decodedImageWithData:data options:options]; } @end diff --git a/Tests/Tests/SDWebImageDecoderTests.m b/Tests/Tests/SDWebImageDecoderTests.m index 5fae2909..13a2bc59 100644 --- a/Tests/Tests/SDWebImageDecoderTests.m +++ b/Tests/Tests/SDWebImageDecoderTests.m @@ -157,7 +157,7 @@ expect([coder canEncodeToFormat:inputImageFormat]).to.beTruthy(); // 4 - encode from UIImage to NSData using the inputImageFormat and check it - NSData *outputImageData = [coder encodedDataWithImage:inputImage format:inputImageFormat]; + NSData *outputImageData = [coder encodedDataWithImage:inputImage format:inputImageFormat options:nil]; expect(outputImageData).toNot.beNil(); UIImage *outputImage = [coder decodedImageWithData:outputImageData options:nil]; expect(outputImage.size).to.equal(inputImage.size); From 4563e714d7ccc87b1c3fa0321026b8a155248c01 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 2 Feb 2018 14:15:29 +0800 Subject: [PATCH 064/361] Support progressive decoding for animated image. A little refactory to make coder protocol more readable --- SDWebImage/NSImage+Additions.h | 3 +- SDWebImage/NSImage+Additions.m | 28 ++-- SDWebImage/SDAnimatedImage.h | 30 +++- SDWebImage/SDAnimatedImage.m | 73 +++++---- SDWebImage/SDAnimatedImageView.m | 163 ++++++++++++++++----- SDWebImage/SDWebImageCoder.h | 27 +++- SDWebImage/SDWebImageCoder.m | 2 +- SDWebImage/SDWebImageCoderHelper.m | 11 +- SDWebImage/SDWebImageCompat.h | 3 - SDWebImage/SDWebImageCompat.m | 62 -------- SDWebImage/SDWebImageDefine.h | 24 ++- SDWebImage/SDWebImageDefine.m | 91 ++++++++++++ SDWebImage/SDWebImageDownloaderOperation.m | 63 +++++--- SDWebImage/SDWebImageGIFCoder.h | 2 +- SDWebImage/SDWebImageGIFCoder.m | 90 ++++++++++-- SDWebImage/SDWebImageImageIOCoder.m | 23 +-- SDWebImage/SDWebImageWebPCoder.m | 39 ++--- SDWebImage/UIImage+WebCache.h | 5 + SDWebImage/UIImage+WebCache.m | 51 ++++--- 19 files changed, 541 insertions(+), 249 deletions(-) diff --git a/SDWebImage/NSImage+Additions.h b/SDWebImage/NSImage+Additions.h index 3a78ce91..a5264ed8 100644 --- a/SDWebImage/NSImage+Additions.h +++ b/SDWebImage/NSImage+Additions.h @@ -17,8 +17,7 @@ @property (nonatomic, readonly, nullable) CGImageRef CGImage; @property (nonatomic, readonly, nullable) NSArray *images; @property (nonatomic, readonly) CGFloat scale; - -- (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale; +@property (nonatomic, readonly, nullable) NSBitmapImageRep *bitmapImageRep; @end diff --git a/SDWebImage/NSImage+Additions.m b/SDWebImage/NSImage+Additions.m index 466a9444..65a66621 100644 --- a/SDWebImage/NSImage+Additions.m +++ b/SDWebImage/NSImage+Additions.m @@ -14,7 +14,7 @@ - (CGImageRef)CGImage { NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); - CGImageRef cgImage = [self CGImageForProposedRect:&imageRect context:NULL hints:nil]; + CGImageRef cgImage = [self CGImageForProposedRect:&imageRect context:nil hints:nil]; return cgImage; } @@ -24,28 +24,22 @@ - (CGFloat)scale { CGFloat scale = 1; - NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); - NSImageRep *rep = [self bestRepresentationForRect:imageRect context:NULL hints:nil]; - NSInteger pixelsWide = rep.pixelsWide; - CGFloat width = rep.size.width; + CGFloat width = self.size.width; if (width > 0) { - scale = pixelsWide / width; + // Use CGImage to get pixel width, NSImageRep.pixelsWide always double on Retina screen + NSUInteger pixelWidth = CGImageGetWidth(self.CGImage); + scale = pixelWidth / width; } return scale; } -- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale { - NSSize size; - if (cgImage && scale > 0) { - NSInteger pixelsWide = CGImageGetWidth(cgImage); - NSInteger pixelsHigh = CGImageGetHeight(cgImage); - CGFloat width = pixelsWide / scale; - CGFloat height = pixelsHigh / scale; - size = NSMakeSize(width, height); - } else { - size = NSZeroSize; +- (NSBitmapImageRep *)bitmapImageRep { + NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); + NSImageRep *imageRep = [self bestRepresentationForRect:imageRect context:nil hints:nil]; + if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) { + return (NSBitmapImageRep *)imageRep; } - return [self initWithCGImage:cgImage size:size]; + return nil; } @end diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h index 47bee11c..d5f75c69 100644 --- a/SDWebImage/SDAnimatedImage.h +++ b/SDWebImage/SDAnimatedImage.h @@ -9,9 +9,18 @@ #import "SDWebImageCompat.h" #import "NSData+ImageContentType.h" +@protocol SDWebImageAnimatedCoder; @protocol SDAnimatedImage @required +/** + The original animated image data for current image. If current image is not an animated format, return nil. + We may use this method to grab back the original image data if need, such as NSCoding or compare. + + @return The animated image data + */ +- (nullable NSData *)animatedImageData; + /** Total animated frame count. It the frame count is less than 1, then the methods below will be ignored. @@ -42,6 +51,7 @@ */ - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index; +// These methods are for SDAnimatedImage class only but not for SDWebImageAnimatedCoder. @optional /** Preload all frame image to memory. Then directly return the frame for index without decoding. @@ -51,6 +61,16 @@ */ - (void)preloadAllFrames; +/** + 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. + + @param animatedCoder An animated coder which conform `SDWebImageAnimatedCoder` protocol + @param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property. (For `NSImage`, `scale` property can be calculated from `size`) + @return An initialized object + */ +- (nullable instancetype)initWithAnimatedCoder:(nonnull id)animatedCoder scale:(CGFloat)scale; + @end @interface SDAnimatedImage : UIImage @@ -63,9 +83,10 @@ - (nullable instancetype)initWithContentsOfFile:(nonnull NSString *)path; - (nullable instancetype)initWithData:(nonnull NSData *)data; - (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale; +- (nullable instancetype)initWithAnimatedCoder:(nonnull id)animatedCoder scale:(CGFloat)scale; /** - Current animated image format + Current animated image format. */ @property (nonatomic, assign, readonly) SDImageFormat animatedImageFormat; /** @@ -73,6 +94,13 @@ */ @property (nonatomic, copy, readonly, nullable) NSData *animatedImageData; +#if SD_MAC +/** + For AppKit, `NSImage` can contains multiple image representations with different scales. However, this class does not do that from the design. We processs the scale like UIKit and store it as a extra information for correctlly rendering in `SDAnimatedImageView`. + */ +@property (nonatomic, readonly) CGFloat scale; +#endif + /** Preload all frame image to memory. Then directly return the frame for index without decoding. The preloaded animated image frames will be removed when receiving memory warning. diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index f69e6380..6a0511a4 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -31,18 +31,9 @@ static CGFloat SDImageScaleFromPath(NSString *string) { @interface SDAnimatedImage () @property (nonatomic, strong) id coder; -@property (nonatomic, assign, readwrite) NSUInteger animatedImageLoopCount; -@property (nonatomic, assign, readwrite) NSUInteger animatedImageFrameCount; -@property (nonatomic, copy, readwrite) NSData *animatedImageData; @property (nonatomic, assign, readwrite) SDImageFormat animatedImageFormat; @property (atomic, copy) NSArray *preloadAnimatedImageFrames; @property (nonatomic, assign) BOOL animatedImageFramesPreloaded; -@property (nonatomic, assign) BOOL animatedImageLoopCountChecked; -@property (nonatomic, assign) BOOL animatedImageFrameCountChecked; - -#if SD_MAC -@property (nonatomic, assign) CGFloat scale; -#endif @end @@ -89,41 +80,64 @@ static CGFloat SDImageScaleFromPath(NSString *string) { if (!data || data.length == 0) { return nil; } + if (scale <= 0) { + scale = 1; + } data = [data copy]; // avoid mutable data + id animatedCoder = nil; for (idcoder in [SDWebImageCodersManager sharedManager].coders) { if ([coder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { if ([coder canDecodeFromData:data]) { - id animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data]; - if (!animatedCoder) { - // check next coder - continue; - } else { - self.coder = animatedCoder; - break; - } + animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data]; + break; } } } - if (!self.coder) { + if (!animatedCoder) { return nil; } - UIImage *image = [self.coder animatedImageFrameAtIndex:0]; + UIImage *image = [animatedCoder animatedImageFrameAtIndex:0]; if (!image) { return nil; } +#if SD_MAC + self = [super initWithCGImage:image.CGImage size:NSZeroSize]; +#else + self = [super initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; +#endif + if (self) { + _coder = animatedCoder; +#if SD_MAC + _scale = scale; +#endif + SDImageFormat format = [NSData sd_imageFormatForImageData:data]; + _animatedImageFormat = format; + } + return self; +} + +- (instancetype)initWithAnimatedCoder:(id)animatedCoder scale:(CGFloat)scale { + if (!animatedCoder) { + return nil; + } if (scale <= 0) { scale = 1; } + UIImage *image = [animatedCoder animatedImageFrameAtIndex:0]; + if (!image) { + return nil; + } #if SD_MAC - self = [super initWithCGImage:image.CGImage scale:scale]; + self = [super initWithCGImage:image.CGImage size:NSZeroSize]; #else self = [super initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; #endif if (self) { + _coder = animatedCoder; #if SD_MAC _scale = scale; #endif - _animatedImageData = data; + NSData *data = [animatedCoder animatedImageData]; SDImageFormat format = [NSData sd_imageFormatForImageData:data]; _animatedImageFormat = format; } @@ -174,20 +188,17 @@ static CGFloat SDImageScaleFromPath(NSString *string) { } #pragma mark - SDAnimatedImage + +- (NSData *)animatedImageData { + return [self.coder animatedImageData]; +} + - (NSUInteger)animatedImageLoopCount { - if (!self.animatedImageLoopCountChecked) { - self.animatedImageLoopCountChecked = YES; - _animatedImageLoopCount = [self.coder animatedImageLoopCount]; - } - return _animatedImageLoopCount; + return [self.coder animatedImageLoopCount]; } - (NSUInteger)animatedImageFrameCount { - if (!self.animatedImageFrameCountChecked) { - self.animatedImageFrameCountChecked = YES; - _animatedImageFrameCount = [self.coder animatedImageFrameCount]; - } - return _animatedImageFrameCount; + return [self.coder animatedImageFrameCount]; } - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index f50e5431..348569e3 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -131,9 +131,11 @@ dispatch_semaphore_signal(self->_lock); @property (nonatomic, assign) NSTimeInterval currentTime; @property (nonatomic, assign) BOOL bufferMiss; @property (nonatomic, assign) BOOL shouldAnimate; +@property (nonatomic, assign) BOOL isProgressive; @property (nonatomic, assign) NSUInteger maxBufferCount; @property (nonatomic, strong) NSOperationQueue *fetchQueue; @property (nonatomic, strong) dispatch_semaphore_t lock; +@property (nonatomic, assign) CGFloat animatedImageScale; #if SD_MAC @property (nonatomic, assign) CVDisplayLinkRef displayLink; #else @@ -202,9 +204,11 @@ dispatch_semaphore_signal(self->_lock); { #if SD_MAC self.wantsLayer = YES; + // Default value from `NSImageView` + self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay; self.imageScaling = NSImageScaleProportionallyDown; + self.imageAlignment = NSImageAlignCenter; #endif - self.maxBufferCount = 0; self.runLoopMode = [[self class] defaultRunLoopMode]; self.lock = dispatch_semaphore_create(1); #if SD_UIKIT @@ -213,27 +217,41 @@ dispatch_semaphore_signal(self->_lock); } -- (void)resetAnimated +- (void)resetAnimatedImage { + self.animatedImage = nil; + self.totalFrameCount = 0; + self.totalLoopCount = 0; + self.currentFrame = nil; + self.currentFrameIndex = 0; + self.currentLoopCount = 0; + self.currentTime = 0; + self.bufferMiss = NO; + self.shouldAnimate = NO; + self.isProgressive = NO; + self.maxBufferCount = 0; + self.animatedImageScale = 1; + [_fetchQueue cancelAllOperations]; + _fetchQueue = nil; LOCK({ - self.animatedImage = nil; - self.totalFrameCount = 0; - self.totalLoopCount = 0; - self.currentFrame = 0; - self.currentFrameIndex = 0; - self.currentLoopCount = 0; - self.currentTime = 0; - self.bufferMiss = NO; - self.shouldAnimate = NO; - self.maxBufferCount = 0; - self.layer.contentsScale = 1; [_frameBuffer removeAllObjects]; _frameBuffer = nil; - [_fetchQueue cancelAllOperations]; - _fetchQueue = nil; }); } +- (void)resetProgressiveImage +{ + self.animatedImage = nil; + self.totalFrameCount = 0; + self.totalLoopCount = 0; + // preserve current state + self.shouldAnimate = NO; + self.isProgressive = YES; + self.maxBufferCount = 0; + self.animatedImageScale = 1; + // preserve buffer cache +} + #pragma mark - Accessors #pragma mark Public @@ -242,33 +260,63 @@ dispatch_semaphore_signal(self->_lock); if (self.image == image) { return; } - [self stopAnimating]; - // Reset all value - [self resetAnimated]; + // Check Progressive coding + self.isProgressive = NO; + if ([image conformsToProtocol:@protocol(SDAnimatedImage)] && image.sd_isIncremental) { + NSData *currentData = [((UIImage *)image) animatedImageData]; + if (currentData) { + NSData *previousData; + if ([self.image conformsToProtocol:@protocol(SDAnimatedImage)]) { + previousData = [((UIImage *)self.image) animatedImageData]; + } + // Check whether to use progressive coding + if (!previousData) { + // If previous data is nil + self.isProgressive = YES; + } else if ([currentData isEqualToData:previousData]) { + // If current data is equal to previous data + self.isProgressive = YES; + } + } + } + + if (self.isProgressive) { + // Reset all value, but keep current state + [self resetProgressiveImage]; + } else { + // Stop animating + [self stopAnimating]; + // Reset all value + [self resetAnimatedImage]; + } + + // We need call super method to keep function. This will impliedly call `setNeedsDisplay`. But we have no way to avoid this when using animated image. So we call `setNeedsDisplay` again at the end. super.image = image; if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { NSUInteger animatedImageFrameCount = ((UIImage *)image).animatedImageFrameCount; + // Check the frame count if (animatedImageFrameCount <= 1) { return; } self.animatedImage = (UIImage *)image; self.totalFrameCount = animatedImageFrameCount; + // Get the current frame and loop count. self.totalLoopCount = self.animatedImage.animatedImageLoopCount; + // Get the scale + self.animatedImageScale = image.scale; + if (!self.isProgressive) { + self.currentFrame = image; + LOCK({ + self.frameBuffer[@(self.currentFrameIndex)] = self.currentFrame; + }); + } + // Ensure disabled highlighting; it's not supported (see `-setHighlighted:`). super.highlighted = NO; // UIImageView seems to bypass some accessors when calculating its intrinsic content size, so this ensures its intrinsic content size comes from the animated image. [self invalidateIntrinsicContentSize]; - // Get the first frame - self.currentFrame = [self.animatedImage animatedImageFrameAtIndex:0]; - LOCK({ - if (self.currentFrame) { - self.frameBuffer[@(0)] = self.currentFrame; - self.bufferMiss = NO; - } else { - self.bufferMiss = YES; - } - }); + // Calculate max buffer size [self calculateMaxBufferCount]; // Update should animate @@ -277,7 +325,6 @@ dispatch_semaphore_signal(self->_lock); [self startAnimating]; } - self.layer.contentsScale = image.scale; [self.layer setNeedsDisplay]; } } @@ -360,6 +407,7 @@ dispatch_semaphore_signal(self->_lock); } #else [_displayLink invalidate]; + _displayLink = nil; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; #endif } @@ -546,9 +594,9 @@ dispatch_semaphore_signal(self->_lock); { if (self.animatedImage) { #if SD_MAC - CVDisplayLinkStop(self.displayLink); + CVDisplayLinkStop(_displayLink); #else - self.displayLink.paused = YES; + _displayLink.paused = YES; #endif } else { #if SD_UIKIT @@ -627,8 +675,9 @@ dispatch_semaphore_signal(self->_lock); #if SD_UIKIT NSTimeInterval duration = displayLink.duration * displayLink.frameInterval; #endif + NSUInteger totalFrameCount = self.totalFrameCount; NSUInteger currentFrameIndex = self.currentFrameIndex; - NSUInteger nextFrameIndex = (currentFrameIndex + 1) % self.totalFrameCount; + NSUInteger nextFrameIndex = (currentFrameIndex + 1) % totalFrameCount; // Check if we have the frame buffer firstly to improve performance if (!self.bufferMiss) { @@ -652,12 +701,17 @@ dispatch_semaphore_signal(self->_lock); LOCK({ currentFrame = self.frameBuffer[@(currentFrameIndex)]; }); + BOOL bufferFull = NO; if (currentFrame) { LOCK({ // Remove the frame buffer if need if (self.frameBuffer.count > self.maxBufferCount) { self.frameBuffer[@(currentFrameIndex)] = nil; } + // Check whether we can stop fetch + if (self.frameBuffer.count == totalFrameCount) { + bufferFull = YES; + } }); self.currentFrame = currentFrame; self.currentFrameIndex = nextFrameIndex; @@ -667,8 +721,19 @@ dispatch_semaphore_signal(self->_lock); self.bufferMiss = YES; } - // Update the loop count - if (nextFrameIndex == 0) { + // Update the loop count when last frame rendered + if (nextFrameIndex == 0 && !self.bufferMiss) { + // Progressive image reach the current last frame index. Keep the state and stop animating. Wait for later restart + if (self.isProgressive) { + // Recovery the current frame index and removed frame buffer (See above) + self.currentFrameIndex = currentFrameIndex; + LOCK({ + self.frameBuffer[@(currentFrameIndex)] = self.currentFrame; + }); + [self stopAnimating]; + return; + } + // Update the loop count self.currentLoopCount++; // if reached the max loop count, stop animating, 0 means loop indefinitely NSUInteger maxLoopCount = self.shouldCustomLoopCount ? self.animationRepeatCount : self.totalLoopCount; @@ -678,13 +743,22 @@ dispatch_semaphore_signal(self->_lock); } } - // Check if we should prefetch next frame - if (self.fetchQueue.operationCount == 0 && self.frameBuffer.count < self.totalFrameCount) { + // Check if we should prefetch next frame or current frame + NSUInteger fetchFrameIndex; + if (self.bufferMiss) { + // When buffer miss, means the decode speed is slower than render speed, we fetch current miss frame + fetchFrameIndex = currentFrameIndex; + } else { + // Or, most cases, the decode speed is faster than render speed, we fetch next frame + fetchFrameIndex = nextFrameIndex; + } + if (!bufferFull && self.fetchQueue.operationCount == 0) { // Prefetch next frame in background queue + UIImage *animatedImage = self.animatedImage; NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ - UIImage *nextFrame = [self.animatedImage animatedImageFrameAtIndex:nextFrameIndex]; + UIImage *fetchFrame = [animatedImage animatedImageFrameAtIndex:fetchFrameIndex]; LOCK({ - self.frameBuffer[@(nextFrameIndex)] = nextFrame; + self.frameBuffer[@(fetchFrameIndex)] = fetchFrame; }); }]; [self.fetchQueue addOperation:operation]; @@ -701,12 +775,15 @@ dispatch_semaphore_signal(self->_lock); #pragma mark - CALayerDelegate (Informal) #pragma mark Providing the Layer's Content +#if SD_UIKIT - (void)displayLayer:(CALayer *)layer { if (_currentFrame) { + layer.contentsScale = self.animatedImageScale; layer.contents = (__bridge id)_currentFrame.CGImage; } } +#endif #if SD_MAC - (BOOL)wantsUpdateLayer @@ -717,7 +794,10 @@ dispatch_semaphore_signal(self->_lock); - (void)updateLayer { if (_currentFrame) { + self.layer.contentsScale = self.animatedImageScale; self.layer.contents = (__bridge id)_currentFrame.CGImage; + } else { + [super updateLayer]; } } #endif @@ -732,13 +812,18 @@ dispatch_semaphore_signal(self->_lock); if (self.maxBufferSize > 0) { max = self.maxBufferSize; } else { - // calculate based on current memory, these factors are by experience + // Calculate based on current memory, these factors are by experience NSUInteger total = SDDeviceTotalMemory(); NSUInteger free = SDDeviceFreeMemory(); max = MIN(total * 0.2, free * 0.6); } NSUInteger maxBufferCount = (double)max / (double)bytes; + if (!maxBufferCount) { + // At least 1 frame + maxBufferCount = 1; + } + self.maxBufferCount = maxBufferCount; } diff --git a/SDWebImage/SDWebImageCoder.h b/SDWebImage/SDWebImageCoder.h index ee6fdd34..0dcaf874 100644 --- a/SDWebImage/SDWebImageCoder.h +++ b/SDWebImage/SDWebImageCoder.h @@ -26,6 +26,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp /** This is the image coder protocol to provide custom image decoding/encoding. These methods are all required to implement. + You do not need to specify image scale during decoding because we may scale image later. @note Pay attention that these methods are not called from main queue. */ @protocol SDWebImageCoder @@ -89,7 +90,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp @param data The image data so we can look at it @return YES if this coder can decode the data, NO otherwise */ -- (BOOL)canIncrementallyDecodeFromData:(nullable NSData *)data; +- (BOOL)canIncrementalDecodeFromData:(nullable NSData *)data; /** Because incremental decoding need to keep the decoded context, we will alloc a new instance with the same class for each download operation to avoid conflicts @@ -97,25 +98,37 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp @return A new instance to do incremental decoding for the specify image format */ -- (nonnull instancetype)initIncrementally; +- (nonnull instancetype)initIncremental; /** - Incremental decode the image data to image. - + Update the incremental decoding when new image data available + @param data The image data has been downloaded so far @param finished Whether the download has finished - @return The decoded image from data */ -- (nullable UIImage *)incrementallyDecodedImageWithData:(nullable NSData *)data finished:(BOOL)finished; +- (void)updateIncrementalData:(nullable NSData *)data finished:(BOOL)finished; + +/** + Incremental decode the current image data to image. + + @param options A dictionary containing any decoding options. + @return The decoded image from current data + */ +- (nullable UIImage *)incrementalDecodedImageWithOptions:(nullable SDWebImageCoderOptions *)options; @end + +/** + This is the animated image coder protocol for custom animated image class like `SDAnimatedImage`. Through it inherit from `SDWebImageCoder`. We currentlly only use the method `canDecodeFromData:` to detect the proper coder for specify animated image format. + */ @protocol SDWebImageAnimatedCoder @required /** Because animated image coder should keep the original data, we will alloc a new instance with the same class for the specify animated image data - The init method should return nil if it can't decode the specify animated image data + The init method should return nil if it can't decode the specify animated image data to produce any frame. + After the instance created, we may call methods in `SDAnimatedImage` to produce animated image frame. @param data The animated image data to be decode @return A new instance to do animated decoding for specify image data diff --git a/SDWebImage/SDWebImageCoder.m b/SDWebImage/SDWebImageCoder.m index 8c8ec4b4..e5d82070 100644 --- a/SDWebImage/SDWebImageCoder.m +++ b/SDWebImage/SDWebImageCoder.m @@ -9,4 +9,4 @@ #import "SDWebImageCoder.h" SDWebImageCoderOption const SDWebImageCoderDecodeFirstFrameOnly = @"decodeFirstFrameOnly"; -SDWebImageCoderOption const SDWebImageCoderEncodeCompressionQuality = @"compressionQuality"; +SDWebImageCoderOption const SDWebImageCoderEncodeCompressionQuality = @"encodeCompressionQuality"; diff --git a/SDWebImage/SDWebImageCoderHelper.m b/SDWebImage/SDWebImageCoderHelper.m index 901fc39a..29f6b739 100644 --- a/SDWebImage/SDWebImageCoderHelper.m +++ b/SDWebImage/SDWebImageCoderHelper.m @@ -197,17 +197,20 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over static CGColorSpaceRef colorSpace; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ -#if SD_MAC +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" BOOL shouldUseSRGB = NO; -#else - BOOL shouldUseSRGB = NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_8_x_Max; +#if SD_UIKIT + NSProcessInfo *processInfo = [NSProcessInfo processInfo]; + shouldUseSRGB = processInfo.operatingSystemVersion.majorVersion >= 9; #endif if (shouldUseSRGB) { - // This is what iOS device used colorspace, combined with right bitmapInfo, even without decode, can still avoid extra CA::Render::copy_image(which marked `Color Copied Images` from Instruments) + // This is what iOS/tvOS device used colorspace, combined with right bitmapInfo, even without decode, can still avoid extra CA::Render::copy_image(which marked `Color Copied Images` from Instruments) colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); } else { colorSpace = CGColorSpaceCreateDeviceRGB(); } +#pragma clang diagnostic pop }); return colorSpace; } diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index 50ef17c2..3e745113 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -83,9 +83,6 @@ #define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type #endif -FOUNDATION_EXPORT CGFloat SDImageScaleForKey(NSString * _Nullable key); -FOUNDATION_EXPORT UIImage * _Nullable SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image); - FOUNDATION_EXPORT NSString *const _Nonnull SDWebImageErrorDomain; #ifndef dispatch_queue_async_safe diff --git a/SDWebImage/SDWebImageCompat.m b/SDWebImage/SDWebImageCompat.m index e54c274d..2997cfb6 100644 --- a/SDWebImage/SDWebImageCompat.m +++ b/SDWebImage/SDWebImageCompat.m @@ -7,8 +7,6 @@ */ #import "SDWebImageCompat.h" -#import "UIImage+WebCache.h" -#import "NSImage+Additions.h" #if !__has_feature(objc_arc) #error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag @@ -18,64 +16,4 @@ #error SDWebImage need ARC for dispatch object #endif -inline CGFloat SDImageScaleForKey(NSString * _Nullable key) { - CGFloat scale = 1; - if (!key) { - return scale; - } -#if SD_WATCH - if ([[WKInterfaceDevice currentDevice] respondsToSelector:@selector(screenScale)]) -#elif SD_UIKIT - if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) -#elif SD_MAC - if ([[NSScreen mainScreen] respondsToSelector:@selector(backingScaleFactor)]) -#endif - { - if (key.length >= 8) { - NSRange range = [key rangeOfString:@"@2x."]; - if (range.location != NSNotFound) { - scale = 2.0; - } - - range = [key rangeOfString:@"@3x."]; - if (range.location != NSNotFound) { - scale = 3.0; - } - } - } - return scale; -} - -inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) { - if (!image) { - return nil; - } - -#if SD_UIKIT || SD_WATCH - if ((image.images).count > 0) { - NSMutableArray *scaledImages = [NSMutableArray array]; - - for (UIImage *tempImage in image.images) { - [scaledImages addObject:SDScaledImageForKey(key, tempImage)]; - } - - UIImage *animatedImage = [UIImage animatedImageWithImages:scaledImages duration:image.duration]; - if (animatedImage) { - animatedImage.sd_imageLoopCount = image.sd_imageLoopCount; - } - return animatedImage; - } -#endif - CGFloat scale = SDImageScaleForKey(key); - if (scale > 1) { -#if SD_UIKIT || SD_WATCH - UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; -#else - UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale]; -#endif - image = scaledImage; - } - return image; -} - NSString *const SDWebImageErrorDomain = @"SDWebImageErrorDomain"; diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index 23a4086c..060df431 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -6,12 +6,34 @@ * file that was distributed with this source code. */ -#import +#import "SDWebImageCompat.h" typedef void(^SDWebImageNoParamsBlock)(void); typedef NSString * SDWebImageContextOption NS_STRING_ENUM; typedef NSDictionary SDWebImageContext; +#pragma mark - Image scale + +/** + Return the image scale from the specify key, supports file name and url key + + @param key The image cache key + @return The scale factor for image + */ +FOUNDATION_EXPORT CGFloat SDImageScaleForKey(NSString * _Nullable key); + +/** + Scale the image with the scale factor from the specify key. If no need to scale, return the original image + This only works for `UIImage`(UIKit) or `NSImage`(AppKit). + + @param key The image cache key + @param image The image + @return The scaled image + */ +FOUNDATION_EXPORT UIImage * _Nullable SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image); + +#pragma mark - Context option + /** A Dispatch group to maintain setImageBlock and completionBlock. This is used for custom setImageBlock advanced usage, such like perform background task but need to guarantee the completion block is called after setImageBlock. (dispatch_group_t) */ diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m index 41be5f9d..edb7414b 100644 --- a/SDWebImage/SDWebImageDefine.m +++ b/SDWebImage/SDWebImageDefine.m @@ -7,6 +7,97 @@ */ #import "SDWebImageDefine.h" +#import "UIImage+WebCache.h" +#import "NSImage+Additions.h" + +#pragma mark - Image scale + +static inline NSArray * _Nonnull SDImageScaleFactors() { + return @[@2, @3]; +} + +inline CGFloat SDImageScaleForKey(NSString * _Nullable key) { + CGFloat scale = 1; + if (!key) { + return scale; + } + // Check if target OS support scale +#if SD_WATCH + if ([[WKInterfaceDevice currentDevice] respondsToSelector:@selector(screenScale)]) +#elif SD_UIKIT + if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) +#elif SD_MAC + if ([[NSScreen mainScreen] respondsToSelector:@selector(backingScaleFactor)]) +#endif + { + // a@2x.png -> 8 + if (key.length >= 8) { + // Fast check + BOOL isURL = [key hasPrefix:@"http://"] || [key hasPrefix:@"https://"]; + for (NSNumber *scaleFactor in SDImageScaleFactors()) { + // @2x. for file name and normal url + NSString *fileScale = [NSString stringWithFormat:@"@%@x.", scaleFactor]; + if ([key containsString:fileScale]) { + scale = scaleFactor.doubleValue; + return scale; + } + if (isURL) { + // %402x. for url encode + NSString *urlScale = [NSString stringWithFormat:@"%%40%@x.", scaleFactor]; + if ([key containsString:urlScale]) { + scale = scaleFactor.doubleValue; + return scale; + } + } + } + } + } + return scale; +} + +inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) { + if (!image) { + return nil; + } + + CGFloat scale = SDImageScaleForKey(key); + if (scale > 1) { + UIImage *scaledImage; + if (image.sd_isAnimated) { + UIImage *animatedImage; +#if SD_UIKIT || SD_WATCH + // `UIAnimatedImage` images share the same size and scale. + NSMutableArray *scaledImages = [NSMutableArray array]; + + for (UIImage *tempImage in image.images) { + UIImage *tempScaledImage = [[UIImage alloc] initWithCGImage:tempImage.CGImage scale:scale orientation:tempImage.imageOrientation]; + [scaledImages addObject:tempScaledImage]; + } + + animatedImage = [UIImage animatedImageWithImages:scaledImages duration:image.duration]; + animatedImage.sd_imageLoopCount = image.sd_imageLoopCount; +#else + // Animated GIF for `NSImage` need to grab `NSBitmapImageRep` + NSSize size = NSMakeSize(image.size.width / scale, image.size.height / scale); + animatedImage = [[NSImage alloc] initWithSize:size]; + NSBitmapImageRep *bitmapImageRep = image.bitmapImageRep; + [animatedImage addRepresentation:bitmapImageRep]; +#endif + scaledImage = animatedImage; + } else { +#if SD_UIKIT || SD_WATCH + scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; +#else + scaledImage = [[NSImage alloc] initWithCGImage:image.CGImage size:NSZeroSize]; +#endif + } + + return scaledImage; + } + return image; +} + +#pragma mark - Context option SDWebImageContextOption const SDWebImageContextSetImageGroup = @"setImageGroup"; SDWebImageContextOption const SDWebImageContextCustomManager = @"customManager"; diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index be454c43..38a58bb2 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -45,6 +45,7 @@ typedef NSMutableDictionary SDCallbacksDictionary; @property (assign, nonatomic, getter = isFinished) BOOL finished; @property (strong, nonatomic, nullable) NSMutableData *imageData; @property (copy, nonatomic, nullable) NSData *cachedData; // for `SDWebImageDownloaderIgnoreCachedResponse` +@property (copy, nonatomic, nullable) NSString *cacheKey; @property (assign, nonatomic, readwrite) NSInteger expectedSize; @property (strong, nonatomic, nullable, readwrite) NSURLResponse *response; @@ -350,22 +351,45 @@ didReceiveResponse:(NSURLResponse *)response // We need to create a new instance for progressive decoding to avoid conflicts for (idcoder in [SDWebImageCodersManager sharedManager].coders) { if ([coder conformsToProtocol:@protocol(SDWebImageProgressiveCoder)] && - [((id)coder) canIncrementallyDecodeFromData:imageData]) { - self.progressiveCoder = [[[coder class] alloc] init]; + [((id)coder) canIncrementalDecodeFromData:imageData]) { + self.progressiveCoder = [[[coder class] alloc] initIncremental]; break; } } } + [self.progressiveCoder updateIncrementalData:imageData finished:finished]; // progressive decode the image in coder queue dispatch_async(self.coderQueue, ^{ - UIImage *image = [self.progressiveCoder incrementallyDecodedImageWithData:imageData finished:finished]; + // check whether we should use `SDAnimatedImage` + UIImage *image; + if ([self.context valueForKey:SDWebImageContextAnimatedImageClass]) { + Class animatedImageClass = [self.context valueForKey:SDWebImageContextAnimatedImageClass]; + if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)] && [animatedImageClass instancesRespondToSelector:@selector(initWithAnimatedCoder:scale:)] && [self.progressiveCoder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { + CGFloat scale = SDImageScaleForKey(self.cacheKey); + image = [[animatedImageClass alloc] initWithAnimatedCoder:(id)self.progressiveCoder scale:scale]; + } + } + if (!image) { + BOOL decodeFirstFrame = self.options & SDWebImageDownloaderDecodeFirstFrameOnly; + image = [self.progressiveCoder incrementalDecodedImageWithOptions:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame)}]; + image = [self scaledImageForKey:self.cacheKey image:image]; + } if (image) { - NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; - image = [self scaledImageForKey:key image:image]; - if (self.shouldDecompressImages) { + BOOL shouldDecode = self.shouldDecompressImages; + if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { + // `SDAnimatedImage` do not decode + shouldDecode = NO; + } else if (image.sd_isAnimated) { + // animated image do not decode + shouldDecode = NO; + } + if (shouldDecode) { image = [SDWebImageCoderHelper decodedImageWithImage:image]; } + if (!finished) { + image.sd_isIncremental = YES; + } // We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding. @@ -431,14 +455,13 @@ didReceiveResponse:(NSURLResponse *)response // decode the image in coder queue dispatch_async(self.coderQueue, ^{ BOOL decodeFirstFrame = self.options & SDWebImageDownloaderDecodeFirstFrameOnly; - NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; UIImage *image; if (!decodeFirstFrame) { // check whether we should use `SDAnimatedImage` if ([self.context valueForKey:SDWebImageContextAnimatedImageClass]) { Class animatedImageClass = [self.context valueForKey:SDWebImageContextAnimatedImageClass]; if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { - CGFloat scale = SDImageScaleForKey(key); + CGFloat scale = SDImageScaleForKey(self.cacheKey); image = [[animatedImageClass alloc] initWithData:imageData scale:scale]; if (self.options & SDWebImageDownloaderPreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { [((id)image) preloadAllFrames]; @@ -448,10 +471,10 @@ didReceiveResponse:(NSURLResponse *)response } if (!image) { image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame)}]; - image = [self scaledImageForKey:key image:image]; + image = [self scaledImageForKey:self.cacheKey image:image]; } - BOOL shouldDecode = YES; + BOOL shouldDecode = self.shouldDecompressImages; if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { // `SDAnimatedImage` do not decode shouldDecode = NO; @@ -459,14 +482,13 @@ didReceiveResponse:(NSURLResponse *)response // animated image do not decode shouldDecode = NO; } + if (shouldDecode) { - if (self.shouldDecompressImages) { - BOOL shouldScaleDown = self.options & SDWebImageDownloaderScaleDownLargeImages; - if (shouldScaleDown) { - image = [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; - } else { - image = [SDWebImageCoderHelper decodedImageWithImage:image]; - } + BOOL shouldScaleDown = self.options & SDWebImageDownloaderScaleDownLargeImages; + if (shouldScaleDown) { + image = [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; + } else { + image = [SDWebImageCoderHelper decodedImageWithImage:image]; } } CGSize imageSize = image.size; @@ -519,6 +541,13 @@ didReceiveResponse:(NSURLResponse *)response } #pragma mark Helper methods +- (NSString *)cacheKey { + if (!_cacheKey) { + _cacheKey = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; + } + return _cacheKey; +} + - (nullable UIImage *)scaledImageForKey:(nullable NSString *)key image:(nullable UIImage *)image { return SDScaledImageForKey(key, image); } diff --git a/SDWebImage/SDWebImageGIFCoder.h b/SDWebImage/SDWebImageGIFCoder.h index 84a9cb69..c92cbcea 100644 --- a/SDWebImage/SDWebImageGIFCoder.h +++ b/SDWebImage/SDWebImageGIFCoder.h @@ -15,7 +15,7 @@ @note Use `SDWebImageGIFCoder` for fully animated GIFs. For `UIImageView`, it will produce animated `UIImage`(`NSImage` on macOS) for rendering. For `SDAnimatedImageView`, it will use `SDAnimatedImage` for rendering. @note The recommended approach for animated GIFs is using `SDAnimatedImage` with `SDAnimatedImageView`. It's more performant than `UIImageView` for GIF displaying(especially on memory usage) */ -@interface SDWebImageGIFCoder : NSObject +@interface SDWebImageGIFCoder : NSObject @property (nonatomic, class, readonly, nonnull) SDWebImageGIFCoder *sharedCoder; diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index 17403262..cfe2d207 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -26,14 +26,12 @@ @implementation SDWebImageGIFCoder { size_t _width, _height; -#if SD_UIKIT || SD_WATCH - UIImageOrientation _orientation; -#endif CGImageSourceRef _imageSource; NSData *_imageData; NSUInteger _loopCount; NSUInteger _frameCount; NSArray *_frames; + BOOL _finished; } - (void)dealloc @@ -167,6 +165,71 @@ return frameDuration; } +#pragma mark - Progressive Decode + +- (BOOL)canIncrementalDecodeFromData:(NSData *)data { + return ([NSData sd_imageFormatForImageData:data] == SDImageFormatGIF); +} + +- (instancetype)initIncremental { + self = [super init]; + if (self) { + _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)}); +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif + } + return self; +} + +- (void)updateIncrementalData:(NSData *)data finished:(BOOL)finished { + if (_finished) { + return; + } + _imageData = data; + _finished = finished; + + // The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/ + // Thanks to the author @Nyx0uf + + // Update the data source, we must pass ALL the data, not just the new bytes + CGImageSourceUpdateData(_imageSource, (__bridge CFDataRef)data, finished); + + if (_width + _height == 0) { + CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(_imageSource, 0, NULL); + if (properties) { + CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight); + if (val) CFNumberGetValue(val, kCFNumberLongType, &_height); + val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth); + if (val) CFNumberGetValue(val, kCFNumberLongType, &_width); + CFRelease(properties); + } + } + + // For animated image progressive decoding because the frame count and duration may be changed. + [self scanAndCheckFramesValidWithImageSource:_imageSource]; +} + +- (UIImage *)incrementalDecodedImageWithOptions:(SDWebImageCoderOptions *)options { + UIImage *image; + + if (_width + _height > 0) { + // Create the image + CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL); + + if (partialImageRef) { +#if SD_UIKIT || SD_WATCH + image = [[UIImage alloc] initWithCGImage:partialImageRef]; +#elif SD_MAC + image = [[UIImage alloc] initWithCGImage:partialImageRef size:NSZeroSize]; +#endif + CGImageRelease(partialImageRef); + } + } + + return image; +} + #pragma mark - Encode - (BOOL)canEncodeToFormat:(SDImageFormat)format { return (format == SDImageFormatGIF); @@ -252,8 +315,7 @@ return self; } -- (BOOL)scanAndCheckFramesValidWithImageSource:(CGImageSourceRef)imageSource -{ +- (BOOL)scanAndCheckFramesValidWithImageSource:(CGImageSourceRef)imageSource { if (!imageSource) { return NO; } @@ -275,26 +337,26 @@ return YES; } -- (NSUInteger)animatedImageLoopCount -{ +- (NSData *)animatedImageData { + return _imageData; +} + +- (NSUInteger)animatedImageLoopCount { return _loopCount; } -- (NSUInteger)animatedImageFrameCount -{ +- (NSUInteger)animatedImageFrameCount { return _frameCount; } -- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index -{ +- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { if (index >= _frameCount) { return 0; } return _frames[index].duration; } -- (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index -{ +- (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { CGImageRef imageRef = CGImageSourceCreateImageAtIndex(_imageSource, index, NULL); if (!imageRef) { return nil; @@ -309,7 +371,7 @@ #if SD_MAC UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef size:NSZeroSize]; #else - UIImage *image = [UIImage imageWithCGImage:newImageRef]; + UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef]; #endif CGImageRelease(newImageRef); return image; diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index b6e2ea5b..0dd5a381 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -19,6 +19,7 @@ #endif CGImageSourceRef _imageSource; NSUInteger _frameCount; + BOOL _finished; } - (void)dealloc { @@ -63,7 +64,7 @@ } } -- (BOOL)canIncrementallyDecodeFromData:(NSData *)data { +- (BOOL)canIncrementalDecodeFromData:(NSData *)data { switch ([NSData sd_imageFormatForImageData:data]) { case SDImageFormatWebP: // Do not support WebP progressive decoding @@ -100,7 +101,7 @@ } #pragma mark - Progressive Decode -- (instancetype)initIncrementally { +- (instancetype)initIncremental { self = [super init]; if (self) { _imageSource = CGImageSourceCreateIncremental(NULL); @@ -111,8 +112,11 @@ return self; } -- (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished { - UIImage *image; +- (void)updateIncrementalData:(NSData *)data finished:(BOOL)finished { + if (_finished) { + return; + } + _finished = finished; // The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/ // Thanks to the author @Nyx0uf @@ -142,6 +146,10 @@ #endif } } +} + +- (UIImage *)incrementalDecodedImageWithOptions:(SDWebImageCoderOptions *)options { + UIImage *image; if (_width + _height > 0) { // Create the image @@ -176,13 +184,6 @@ } } - if (finished) { - if (_imageSource) { - CFRelease(_imageSource); - _imageSource = NULL; - } - } - return image; } diff --git a/SDWebImage/SDWebImageWebPCoder.m b/SDWebImage/SDWebImageWebPCoder.m index 47af8ea2..cf295292 100644 --- a/SDWebImage/SDWebImageWebPCoder.m +++ b/SDWebImage/SDWebImageWebPCoder.m @@ -57,6 +57,7 @@ dispatch_semaphore_signal(self->_lock); CGContextRef _canvas; BOOL _hasAnimation; BOOL _hasAlpha; + BOOL _finished; CGFloat _canvasWidth; CGFloat _canvasHeight; dispatch_semaphore_t _lock; @@ -92,7 +93,7 @@ dispatch_semaphore_signal(self->_lock); return ([NSData sd_imageFormatForImageData:data] == SDImageFormatWebP); } -- (BOOL)canIncrementallyDecodeFromData:(NSData *)data { +- (BOOL)canIncrementalDecodeFromData:(NSData *)data { return ([NSData sd_imageFormatForImageData:data] == SDImageFormatWebP); } @@ -176,7 +177,7 @@ dispatch_semaphore_signal(self->_lock); } #pragma mark - Progressive Decode -- (instancetype)initIncrementally { +- (instancetype)initIncremental { self = [super init]; if (self) { // Progressive images need transparent, so always use premultiplied RGBA @@ -185,16 +186,24 @@ dispatch_semaphore_signal(self->_lock); return self; } -- (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished { - if (!_idec) { - return nil; +- (void)updateIncrementalData:(NSData *)data finished:(BOOL)finished { + if (_finished) { + return; } - UIImage *image; - + _imageData = data; + _finished = finished; VP8StatusCode status = WebPIUpdate(_idec, data.bytes, data.length); if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) { - return nil; + return; } +} + +- (BOOL)incrementalFinished { + return _finished; +} + +- (UIImage *)incrementalDecodedImageWithOptions:(SDWebImageCoderOptions *)options { + UIImage *image; int width = 0; int height = 0; @@ -250,13 +259,6 @@ dispatch_semaphore_signal(self->_lock); CGContextRelease(canvas); } - if (finished) { - if (_idec) { - WebPIDelete(_idec); - _idec = NULL; - } - } - return image; } @@ -517,8 +519,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { return self; } -- (BOOL)scanAndCheckFramesValidWithDemuxer:(WebPDemuxer *)demuxer -{ +- (BOOL)scanAndCheckFramesValidWithDemuxer:(WebPDemuxer *)demuxer { if (!demuxer) { return NO; } @@ -586,6 +587,10 @@ static void FreeImageData(void *info, const void *data, size_t size) { return YES; } +- (NSData *)animatedImageData { + return _imageData; +} + - (NSUInteger)animatedImageLoopCount { return _loopCount; } diff --git a/SDWebImage/UIImage+WebCache.h b/SDWebImage/UIImage+WebCache.h index efa1c4c6..0c7bf351 100644 --- a/SDWebImage/UIImage+WebCache.h +++ b/SDWebImage/UIImage+WebCache.h @@ -29,4 +29,9 @@ */ @property (nonatomic, assign, readonly) BOOL sd_isAnimated; +/** + Indicating whether the image is during incremental decoding and may not contains full pixels. + */ +@property (nonatomic, assign) BOOL sd_isIncremental; + @end diff --git a/SDWebImage/UIImage+WebCache.m b/SDWebImage/UIImage+WebCache.m index 60d3e2f7..c7a82779 100644 --- a/SDWebImage/UIImage+WebCache.m +++ b/SDWebImage/UIImage+WebCache.m @@ -7,11 +7,11 @@ */ #import "UIImage+WebCache.h" +#import "NSImage+Additions.h" +#import "objc/runtime.h" #if SD_UIKIT -#import "objc/runtime.h" - @implementation UIImage (WebCache) - (NSUInteger)sd_imageLoopCount { @@ -32,6 +32,15 @@ return (self.images != nil); } +- (void)setSd_isIncremental:(BOOL)sd_isIncremental { + objc_setAssociatedObject(self, @selector(sd_isIncremental), @(sd_isIncremental), OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (BOOL)sd_isIncremental { + NSNumber *value = objc_getAssociatedObject(self, @selector(sd_isIncremental)); + return value.boolValue; +} + @end #endif @@ -42,39 +51,39 @@ - (NSUInteger)sd_imageLoopCount { NSUInteger imageLoopCount = 0; - for (NSImageRep *rep in self.representations) { - if ([rep isKindOfClass:[NSBitmapImageRep class]]) { - NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep; - imageLoopCount = [[bitmapRep valueForProperty:NSImageLoopCount] unsignedIntegerValue]; - break; - } + NSBitmapImageRep *bitmapImageRep = self.bitmapImageRep; + if (bitmapImageRep) { + imageLoopCount = [[bitmapImageRep valueForProperty:NSImageLoopCount] unsignedIntegerValue]; } return imageLoopCount; } - (void)setSd_imageLoopCount:(NSUInteger)sd_imageLoopCount { - for (NSImageRep *rep in self.representations) { - if ([rep isKindOfClass:[NSBitmapImageRep class]]) { - NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep; - [bitmapRep setProperty:NSImageLoopCount withValue:@(sd_imageLoopCount)]; - break; - } + NSBitmapImageRep *bitmapImageRep = self.bitmapImageRep; + if (bitmapImageRep) { + [bitmapImageRep setProperty:NSImageLoopCount withValue:@(sd_imageLoopCount)]; } } - (BOOL)sd_isAnimated { BOOL isGIF = NO; - for (NSImageRep *rep in self.representations) { - if ([rep isKindOfClass:[NSBitmapImageRep class]]) { - NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep; - NSUInteger frameCount = [[bitmapRep valueForProperty:NSImageFrameCount] unsignedIntegerValue]; - isGIF = frameCount > 1 ? YES : NO; - break; - } + NSBitmapImageRep *bitmapImageRep = self.bitmapImageRep; + if (bitmapImageRep) { + NSUInteger frameCount = [[bitmapImageRep valueForProperty:NSImageFrameCount] unsignedIntegerValue]; + isGIF = frameCount > 1 ? YES : NO; } return isGIF; } +- (void)setSd_isIncremental:(BOOL)sd_isIncremental { + objc_setAssociatedObject(self, @selector(sd_isIncremental), @(sd_isIncremental), OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (BOOL)sd_isIncremental { + NSNumber *value = objc_getAssociatedObject(self, @selector(sd_isIncremental)); + return value.boolValue; +} + @end #endif From 7e83d78ca3075c3c7b98ff28ad0179b11b22e41c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 17 Feb 2018 13:50:00 +0800 Subject: [PATCH 065/361] Add tests about SDAnimatedImage SDAnimatedImageView and SDAnimatedImage+WebCache --- SDWebImage/SDAnimatedImage.h | 10 +- SDWebImage/SDWebImageDownloaderOperation.m | 5 +- .../project.pbxproj | 4 + Tests/Tests/SDAnimatedImageTest.m | 232 ++++++++++++++++++ Tests/Tests/SDTestCase.h | 2 + Tests/Tests/SDTestCase.m | 2 + Tests/Tests/SDWebImageTestDecoder.m | 10 +- 7 files changed, 254 insertions(+), 11 deletions(-) create mode 100644 Tests/Tests/SDAnimatedImageTest.m diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h index d5f75c69..7e390d1e 100644 --- a/SDWebImage/SDAnimatedImage.h +++ b/SDWebImage/SDAnimatedImage.h @@ -54,10 +54,10 @@ // These methods are for SDAnimatedImage class only but not for SDWebImageAnimatedCoder. @optional /** - Preload all frame image to memory. Then directly return the frame for index without decoding. + Preload all frame image to memory. Then later 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. + @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. */ - (void)preloadAllFrames; @@ -102,11 +102,11 @@ #endif /** - Preload all frame image to memory. Then directly return the frame for index without decoding. + 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. - @note Once preload the frames into memory, there is no huge differenec on performance between UIImage's `animatedImageWithImages:duration:` for UIKit. But UIImage's animation have some issue such like blanking or frame resetting. It's recommend to use only if need. + @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. */ - (void)preloadAllFrames; diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 38a58bb2..d0f36d7c 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -387,9 +387,8 @@ didReceiveResponse:(NSURLResponse *)response if (shouldDecode) { image = [SDWebImageCoderHelper decodedImageWithImage:image]; } - if (!finished) { - image.sd_isIncremental = YES; - } + // mark the image as progressive (completionBlock one are not mark as progressive) + image.sd_isIncremental = YES; // We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding. diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 5ce63173..06c14c7a 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ 32B99EAC203B36650017FD66 /* SDWebImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */; }; 32B99EAD203B36690017FD66 /* SDWebImagePrefetcherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */; }; 32B99EAE203B366C0017FD66 /* SDWebCacheCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */; }; + 32A571562037DB2D002EDAAE /* SDAnimatedImageTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */; }; 32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */; }; 37D122881EC48B5E00D98CEB /* SDMockFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */; }; 433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */; }; @@ -66,6 +67,7 @@ 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDCategoriesTests.m; sourceTree = ""; }; 32B99E92203B2DF90017FD66 /* Tests Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 32B99E96203B2DF90017FD66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImageTest.m; sourceTree = ""; }; 32E6F0301F3A1B4700A945E6 /* SDWebImageTestDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestDecoder.h; sourceTree = ""; }; 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestDecoder.m; sourceTree = ""; }; 37D122861EC48B5E00D98CEB /* SDMockFileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDMockFileManager.h; sourceTree = ""; }; @@ -195,6 +197,7 @@ 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */, 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */, 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */, + 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */, 37D122861EC48B5E00D98CEB /* SDMockFileManager.h */, 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */, 2D7AF05E1F329763000083C2 /* SDTestCase.h */, @@ -469,6 +472,7 @@ files = ( 32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */, 3254C32020641077008D1022 /* SDWebImageTransformerTests.m in Sources */, + 32A571562037DB2D002EDAAE /* SDAnimatedImageTest.m in Sources */, 1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */, 37D122881EC48B5E00D98CEB /* SDMockFileManager.m in Sources */, 4369C2741D9804B1007E863A /* SDWebCacheCategoriesTests.m in Sources */, diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m new file mode 100644 index 00000000..5f15bc0b --- /dev/null +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -0,0 +1,232 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Matt Galloway + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDTestCase.h" +#import +#import +#import +#import +#import +#import + +static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop count + +@interface SDAnimatedImageTest : SDTestCase + +@property (nonatomic, strong) UIWindow *window; + +@end + +@implementation SDAnimatedImageTest + +- (void)tearDown { + [[SDImageCache sharedImageCache] removeImageForKey:kTestGIFURL fromDisk:YES withCompletion:nil]; + [[SDImageCache sharedImageCache] removeImageForKey:kTestWebPURL fromDisk:YES withCompletion:nil]; +} + +- (void)test01AnimatedImageInitWithData { + NSData *invalidData = [@"invalid data" dataUsingEncoding:NSUTF8StringEncoding]; + SDAnimatedImage *image = [[SDAnimatedImage alloc] initWithData:invalidData]; + expect(image).beNil(); + + NSData *validData = [self testGIFData]; + image = [[SDAnimatedImage alloc] initWithData:validData scale:2]; + expect(image).notTo.beNil(); // image + expect(image.scale).equal(2); // scale + expect(image.animatedImageData).equal(validData); // data + expect(image.animatedImageFormat).equal(SDImageFormatGIF); // format + expect(image.animatedImageLoopCount).equal(0); // loop count + expect(image.animatedImageFrameCount).equal(kTestGIFFrameCount); // frame count + expect([image animatedImageFrameAtIndex:1]).notTo.beNil(); // 1 frame +} + +- (void)test02AnimatedImageInitWithContentsOfFile { + SDAnimatedImage *image = [[SDAnimatedImage alloc] initWithContentsOfFile:[self testGIFPath]]; + expect(image).notTo.beNil(); + expect(image.scale).equal(1); // scale + // enough, other can be test with InitWithData +} + +- (void)test03AnimatedImageInitWithAnimatedCoder { + NSData *validData = [self testGIFData]; + SDWebImageGIFCoder *coder = [[SDWebImageGIFCoder alloc] initWithAnimatedImageData:validData]; + SDAnimatedImage *image = [[SDAnimatedImage alloc] initWithAnimatedCoder:coder scale:1]; + expect(image).notTo.beNil(); + // enough, other can be test with InitWithData +} + +- (void)test04AnimatedImagePreloadFrames { + NSData *validData = [self testGIFData]; + SDAnimatedImage *image = [SDAnimatedImage imageWithData:validData]; + + // Preload all frames + [image preloadAllFrames]; + + NSArray *preloadAnimatedImageFrames = [image valueForKey:@"preloadAnimatedImageFrames"]; + expect(preloadAnimatedImageFrames.count).equal(kTestGIFFrameCount); + + // Test one frame + UIImage *frame = [image animatedImageFrameAtIndex:0]; + expect(frame).notTo.beNil(); +} + +- (void)test05AnimatedImageViewSetImage { + SDAnimatedImageView *imageView = [SDAnimatedImageView new]; + UIImage *image = [UIImage imageWithData:[self testJPEGData]]; + imageView.image = image; + expect(imageView.image).notTo.beNil(); + expect(imageView.currentFrame).beNil(); // current frame +} + +- (void)test06AnimatedImageViewSetAnimatedImage { + SDAnimatedImageView *imageView = [SDAnimatedImageView new]; + SDAnimatedImage *image = [SDAnimatedImage imageWithData:[self testAnimatedWebPData]]; + imageView.image = image; + expect(imageView.image).notTo.beNil(); + expect(imageView.currentFrame).notTo.beNil(); // current frame +} + +- (void)test07AnimatedImageViewRendering { + XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView rendering"]; + SDAnimatedImageView *imageView = [[SDAnimatedImageView alloc] init]; + [self.window addSubview:imageView]; + + NSMutableDictionary *frames = [NSMutableDictionary dictionaryWithCapacity:kTestGIFFrameCount]; + + [self.KVOController observe:imageView keyPaths:@[NSStringFromSelector(@selector(currentFrameIndex)), NSStringFromSelector(@selector(currentLoopCount))] options:NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionary * _Nonnull change) { + NSUInteger frameIndex = imageView.currentFrameIndex; + NSUInteger loopCount = imageView.currentLoopCount; + [frames setObject:@(YES) forKey:@(frameIndex)]; + + BOOL framesRendered = NO; + if (frames.count >= kTestGIFFrameCount) { + // All frames rendered + framesRendered = YES; + } + BOOL loopFinished = NO; + if (loopCount >= 1) { + // One loop finished + loopFinished = YES; + } + if (framesRendered && loopFinished) { + [imageView stopAnimating]; + [expectation fulfill]; + } + }]; + + SDAnimatedImage *image = [SDAnimatedImage imageWithData:[self testGIFData]]; + imageView.image = image; + + [self waitForExpectationsWithCommonTimeout]; +} + +- (void)test08AnimatedImageViewSetProgressiveAnimatedImage { + NSData *gifData = [self testGIFData]; + SDWebImageGIFCoder *progressiveCoder = [[SDWebImageGIFCoder alloc] initIncremental]; + // simulate progressive decode, pass partial data + NSData *partialData = [gifData subdataWithRange:NSMakeRange(0, gifData.length - 1)]; + [progressiveCoder updateIncrementalData:partialData finished:NO]; + + SDAnimatedImage *partialImage = [[SDAnimatedImage alloc] initWithAnimatedCoder:progressiveCoder scale:1]; + partialImage.sd_isIncremental = YES; + + SDAnimatedImageView *imageView = [[SDAnimatedImageView alloc] init]; + imageView.image = partialImage; + + BOOL isProgressive = [[imageView valueForKey:@"isProgressive"] boolValue]; + expect(isProgressive).equal(YES); + + // pass full data + [progressiveCoder updateIncrementalData:gifData finished:YES]; + + SDAnimatedImage *fullImage = [[SDAnimatedImage alloc] initWithAnimatedCoder:progressiveCoder scale:1]; + + imageView.image = fullImage; + + isProgressive = [[imageView valueForKey:@"isProgressive"] boolValue]; + expect(isProgressive).equal(NO); +} + +- (void)test09AnimatedImageViewCategory { + XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"]; + SDAnimatedImageView *imageView = [SDAnimatedImageView new]; + NSURL *testURL = [NSURL URLWithString:kTestWebPURL]; + [imageView sd_setImageWithURL:testURL completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { + expect(error).to.beNil(); + expect(image).notTo.beNil(); + expect([image isKindOfClass:[SDAnimatedImage class]]).beTruthy(); + [expectation fulfill]; + }]; + [self waitForExpectationsWithCommonTimeout]; +} + +- (void)test10AnimatedImageViewCategoryProgressive { + XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"]; + SDAnimatedImageView *imageView = [SDAnimatedImageView new]; + NSURL *testURL = [NSURL URLWithString:kTestGIFURL]; + [imageView sd_setImageWithURL:testURL placeholderImage:nil options:SDWebImageProgressiveDownload progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { + dispatch_async(dispatch_get_main_queue(), ^{ + UIImage *image = imageView.image; + // Progressive image may be nil when download data is not enough + if (image) { + expect(image.sd_isIncremental).beTruthy(); + BOOL isProgressive = [[imageView valueForKey:@"isProgressive"] boolValue]; + expect(isProgressive).equal(YES); + } + }); + } completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { + expect(error).to.beNil(); + expect(image).notTo.beNil(); + expect([image isKindOfClass:[SDAnimatedImage class]]).beTruthy(); + [expectation fulfill]; + }]; + [self waitForExpectationsWithCommonTimeout]; +} + +#pragma mark - Helper +- (UIWindow *)window { + if (!_window) { + _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + } + return _window; +} + +- (NSString *)testGIFPath { + NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; + NSString *testPath = [testBundle pathForResource:@"TestImage" ofType:@"gif"]; + return testPath; +} + +- (NSData *)testGIFData { + NSData *testData = [NSData dataWithContentsOfFile:[self testGIFPath]]; + return testData; +} + +- (NSString *)testAnimatedWebPPath { + NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; + NSString *testPath = [testBundle pathForResource:@"TestImageAnimated" ofType:@"webp"]; + return testPath; +} + +- (NSData *)testAnimatedWebPData { + return [NSData dataWithContentsOfFile:[self testAnimatedWebPPath]]; +} + +- (NSString *)testJPEGPath { + NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; + NSString *testPath = [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; + return testPath; +} + +- (NSData *)testJPEGData { + NSData *testData = [NSData dataWithContentsOfFile:[self testJPEGPath]]; + return testData; +} + +@end diff --git a/Tests/Tests/SDTestCase.h b/Tests/Tests/SDTestCase.h index e17b517f..dbb7c36b 100644 --- a/Tests/Tests/SDTestCase.h +++ b/Tests/Tests/SDTestCase.h @@ -17,6 +17,8 @@ FOUNDATION_EXPORT const int64_t kAsyncTestTimeout; FOUNDATION_EXPORT const int64_t kMinDelayNanosecond; FOUNDATION_EXPORT NSString * _Nonnull const kTestJpegURL; FOUNDATION_EXPORT NSString * _Nonnull const kTestPNGURL; +FOUNDATION_EXPORT NSString * _Nonnull const kTestGIFURL; +FOUNDATION_EXPORT NSString * _Nonnull const kTestWebPURL; @interface SDTestCase : XCTestCase diff --git a/Tests/Tests/SDTestCase.m b/Tests/Tests/SDTestCase.m index c44b0913..fbdb2945 100644 --- a/Tests/Tests/SDTestCase.m +++ b/Tests/Tests/SDTestCase.m @@ -13,6 +13,8 @@ const int64_t kAsyncTestTimeout = 5; const int64_t kMinDelayNanosecond = NSEC_PER_MSEC * 100; // 0.1s NSString *const kTestJpegURL = @"http://via.placeholder.com/50x50.jpg"; NSString *const kTestPNGURL = @"http://via.placeholder.com/50x50.png"; +NSString *const kTestGIFURL = @"https://media.giphy.com/media/UEsrLdv7ugRTq/giphy.gif"; +NSString *const kTestWebPURL = @"http://littlesvr.ca/apng/images/SteamEngine.webp"; @implementation SDTestCase diff --git a/Tests/Tests/SDWebImageTestDecoder.m b/Tests/Tests/SDWebImageTestDecoder.m index 4cc494b3..1ccd5043 100644 --- a/Tests/Tests/SDWebImageTestDecoder.m +++ b/Tests/Tests/SDWebImageTestDecoder.m @@ -25,7 +25,7 @@ return image; } -- (instancetype)initIncrementally +- (instancetype)initIncremental { self = [super init]; if (self) { @@ -33,13 +33,17 @@ return self; } -- (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished { +- (void)updateIncrementalData:(NSData *)data finished:(BOOL)finished { + return; +} + +- (UIImage *)incrementalDecodedImageWithOptions:(SDWebImageCoderOptions *)options { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"gif"]; UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; return image; } -- (BOOL)canIncrementallyDecodeFromData:(nullable NSData *)data { +- (BOOL)canIncrementalDecodeFromData:(NSData *)data { return YES; } From 5e09c6bf196b085294b2d81ea619dc5ad4a673f1 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 22 Feb 2018 19:28:07 +0800 Subject: [PATCH 066/361] Add support for imageNamed: in SDAnimatedImage with bundle files --- SDWebImage/SDAnimatedImage.h | 15 ++- SDWebImage/SDAnimatedImage.m | 217 ++++++++++++++++++++++++++++++ SDWebImage/SDAnimatedImageView.h | 2 + SDWebImage/SDAnimatedImageView.m | 5 +- SDWebImage/SDWebImageDefine.h | 2 +- Tests/Tests/SDAnimatedImageTest.m | 20 ++- 6 files changed, 246 insertions(+), 15 deletions(-) diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h index 7e390d1e..629f2d18 100644 --- a/SDWebImage/SDAnimatedImage.h +++ b/SDWebImage/SDAnimatedImage.h @@ -66,7 +66,7 @@ @note Normally we use `initWithData:scale:` to create custom animated image class. So you can implement your custom class without our built-in coder. @param animatedCoder An animated coder which conform `SDWebImageAnimatedCoder` protocol - @param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property. (For `NSImage`, `scale` property can be calculated from `size`) + @param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property. @return An initialized object */ - (nullable instancetype)initWithAnimatedCoder:(nonnull id)animatedCoder scale:(CGFloat)scale; @@ -76,7 +76,11 @@ @interface SDAnimatedImage : UIImage // This class override these methods from UIImage(NSImage), and it supports NSSecureCoding. -// You should use these methods to create a new animated image. Use other methods will just call super instead. +// You should use these methods to create a new animated image. Use other methods just call super instead. ++ (nullable instancetype)imageNamed:(nonnull NSString *)name; // Cache in memory, no Asset Catalog support +#if __has_include() ++ (nullable instancetype)imageNamed:(nonnull NSString *)name inBundle:(nullable NSBundle *)bundle compatibleWithTraitCollection:(nullable UITraitCollection *)traitCollection; // Cache in memory, no Asset Catalog support +#endif + (nullable instancetype)imageWithContentsOfFile:(nonnull NSString *)path; + (nullable instancetype)imageWithData:(nonnull NSData *)data; + (nullable instancetype)imageWithData:(nonnull NSData *)data scale:(CGFloat)scale; @@ -94,12 +98,13 @@ */ @property (nonatomic, copy, readonly, nullable) NSData *animatedImageData; -#if SD_MAC /** - For AppKit, `NSImage` can contains multiple image representations with different scales. However, this class does not do that from the design. We processs the scale like UIKit and store it as a extra information for correctlly rendering in `SDAnimatedImageView`. + The scale factor of the image. + + @note For UIKit, this just call super instead. + @note For AppKit, `NSImage` can contains multiple image representations with different scales. However, this class does not do that from the design. We processs the scale like UIKit and store it as a extra information for correctlly rendering in `SDAnimatedImageView`. */ @property (nonatomic, readonly) CGFloat scale; -#endif /** Preload all frame image to memory. Then later request can directly return the frame for index without decoding. diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index 6a0511a4..2d78779e 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -13,6 +13,10 @@ #import "SDWebImageCodersManager.h" #import "SDWebImageFrame.h" +#define LOCK(...) dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER); \ +__VA_ARGS__; \ +dispatch_semaphore_signal(self->_lock); + static CGFloat SDImageScaleFromPath(NSString *string) { if (string.length == 0 || [string hasSuffix:@"/"]) return 1; NSString *name = string.stringByDeletingPathExtension; @@ -28,6 +32,169 @@ static CGFloat SDImageScaleFromPath(NSString *string) { return scale; } +static NSArray *SDBundlePreferredScales() { + static NSArray *scales; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ +#if SD_WATCH + CGFloat screenScale = [WKInterfaceDevice currentDevice].screenScale; +#elif SD_UIKIT + CGFloat screenScale = [UIScreen mainScreen].scale; +#elif SD_MAC + CGFloat screenScale = [NSScreen mainScreen].backingScaleFactor; +#endif + if (screenScale <= 1) { + scales = @[@1,@2,@3]; + } else if (screenScale <= 2) { + scales = @[@2,@3,@1]; + } else { + scales = @[@3,@2,@1]; + } + }); + return scales; +} + +#pragma mark - UIImage cache for bundle + +// Apple parse the Asset Catalog compiled file(`Assets.car`) by CoreUI.framework, however it's a private framework and there are no other ways to directly get the data. So we just process the normal bundle files :) + +@interface SDImageAssetManager : NSObject { + dispatch_semaphore_t _lock; +} + +@property (nonatomic, strong) NSMapTable *imageTable; + ++ (instancetype)sharedAssetManager; +- (nullable NSString *)getPathForName:(nonnull NSString *)name bundle:(nonnull NSBundle *)bundle preferredScale:(CGFloat *)scale; +- (nullable UIImage *)imageForName:(nonnull NSString *)name; +- (void)storeImage:(nonnull UIImage *)image forName:(nonnull NSString *)name; + +@end + +@implementation SDImageAssetManager + ++ (instancetype)sharedAssetManager { + static dispatch_once_t onceToken; + static SDImageAssetManager *assetManager; + dispatch_once(&onceToken, ^{ + assetManager = [[SDImageAssetManager alloc] init]; + }); + return assetManager; +} + +- (instancetype)init { + self = [super init]; + if (self) { + NSPointerFunctionsOptions valueOptions; +#if SD_MAC + // Apple says that NSImage use a weak reference to value + valueOptions = NSPointerFunctionsWeakMemory; +#else + // Apple says that UIImage use a strong reference to value + valueOptions = NSPointerFunctionsStrongMemory; +#endif + _imageTable = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsCopyIn valueOptions:valueOptions]; + _lock = dispatch_semaphore_create(1); +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif + } + return self; +} + +- (void)dealloc { +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif +} + +- (void)didReceiveMemoryWarning:(NSNotification *)notification { + LOCK({ + [self.imageTable removeAllObjects]; + }); +} + +- (NSString *)getPathForName:(NSString *)name bundle:(NSBundle *)bundle preferredScale:(CGFloat *)scale { + NSParameterAssert(name); + NSParameterAssert(bundle); + NSString *path; + if (name.length == 0) { + return path; + } + if ([name hasSuffix:@"/"]) { + return path; + } + NSString *extension = name.pathExtension; + if (extension.length == 0) { + // If no extension, follow Apple's doc, check PNG format + extension = @"png"; + } + name = [name stringByDeletingPathExtension]; + + CGFloat providedScale = *scale; + NSArray *scales = SDBundlePreferredScales(); + + // Check if file name contains scale + for (size_t i = 0; i < scales.count; i++) { + NSNumber *scaleValue = scales[i]; + if ([name hasSuffix:[NSString stringWithFormat:@"@%@x", scaleValue]]) { + path = [bundle pathForResource:name ofType:extension]; + if (path) { + *scale = scaleValue.doubleValue; // override + return path; + } + } + } + + // Search with provided scale first + if (providedScale != 0) { + NSString *scaledName = [name stringByAppendingFormat:@"@%@x", @(providedScale)]; + path = [bundle pathForResource:scaledName ofType:extension]; + if (path) { + return path; + } + } + + // Search with preferred scale + for (size_t i = 0; i < scales.count; i++) { + NSNumber *scaleValue = scales[i]; + if (scaleValue.doubleValue == providedScale) { + // Ignore provided scale + continue; + } + NSString *scaledName = [name stringByAppendingFormat:@"@%@x", scaleValue]; + path = [bundle pathForResource:scaledName ofType:extension]; + if (path) { + *scale = scaleValue.doubleValue; // override + return path; + } + } + + // Search without scale + path = [bundle pathForResource:name ofType:extension]; + + return path; +} + +- (UIImage *)imageForName:(NSString *)name { + NSParameterAssert(name); + UIImage *image; + LOCK({ + image = [self.imageTable objectForKey:name]; + }); + return image; +} + +- (void)storeImage:(UIImage *)image forName:(NSString *)name { + NSParameterAssert(image); + NSParameterAssert(name); + LOCK({ + [self.imageTable setObject:image forKey:name]; + }); +} + +@end + @interface SDAnimatedImage () @property (nonatomic, strong) id coder; @@ -38,6 +205,9 @@ static CGFloat SDImageScaleFromPath(NSString *string) { @end @implementation SDAnimatedImage +#if SD_UIKIT || SD_WATCH +@dynamic scale; // call super +#endif #pragma mark - Dealloc & Memory warning @@ -55,6 +225,53 @@ static CGFloat SDImageScaleFromPath(NSString *string) { } #pragma mark - UIImage override method ++ (instancetype)imageNamed:(NSString *)name { +#if __has_include() + return [self imageNamed:name inBundle:nil compatibleWithTraitCollection:nil]; +#else + return [self imageNamed:name inBundle:nil scale:0]; +#endif +} + +#if __has_include() ++ (instancetype)imageNamed:(NSString *)name inBundle:(NSBundle *)bundle compatibleWithTraitCollection:(UITraitCollection *)traitCollection { + if (!traitCollection) { + traitCollection = UIScreen.mainScreen.traitCollection; + } + CGFloat scale = traitCollection.displayScale; + return [self imageNamed:name inBundle:bundle scale:scale]; +} +#endif + +// 0 scale means automatically check ++ (instancetype)imageNamed:(NSString *)name inBundle:(NSBundle *)bundle scale:(CGFloat)scale { + if (!name) { + return nil; + } + if (!bundle) { + bundle = [NSBundle mainBundle]; + } + SDImageAssetManager *assetManager = [SDImageAssetManager sharedAssetManager]; + SDAnimatedImage *image = (SDAnimatedImage *)[assetManager imageForName:name]; + if ([image isKindOfClass:[SDAnimatedImage class]]) { + return image; + } + NSString *path = [assetManager getPathForName:name bundle:bundle preferredScale:&scale]; + if (!path) { + return image; + } + NSData *data = [NSData dataWithContentsOfFile:path]; + if (!data) { + return image; + } + image = [[self alloc] initWithData:data scale:scale]; + if (image) { + [assetManager storeImage:image forName:name]; + } + + return image; +} + + (instancetype)imageWithContentsOfFile:(NSString *)path { return [[self alloc] initWithContentsOfFile:path]; } diff --git a/SDWebImage/SDAnimatedImageView.h b/SDWebImage/SDAnimatedImageView.h index 9c30b394..28748d19 100644 --- a/SDWebImage/SDAnimatedImageView.h +++ b/SDWebImage/SDAnimatedImageView.h @@ -10,6 +10,8 @@ #if SD_UIKIT || SD_MAC +#import "SDAnimatedImage.h" + /** A drop-in replacement for UIImageView/NSImageView, you can use this for animated image rendering. Call `setImage:` with a `UIImage` will start animated image rendering. Call with a UIImage(NSImage) will back to normal UIImageView(NSImageView) rendering diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index 348569e3..69b80a5f 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -7,10 +7,11 @@ */ #import "SDAnimatedImageView.h" + +#if SD_UIKIT || SD_MAC + #import "UIImage+WebCache.h" #import "NSImage+Additions.h" -#if SD_UIKIT || SD_MAC -#import "SDAnimatedImage.h" #import #if SD_MAC diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index 060df431..ae5dfd0d 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -50,7 +50,7 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustom FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustomTransformer; /** - A Class object which the instance is a `UIImage/NSImage` subclass and adopt `SDAnimatedImage` protocol. And call `initWithData:scale:` to create the instance. If the instance create failed, fallback to normal `UIImage/NSImage`. + A Class object which the instance is a `UIImage/NSImage` subclass and adopt `SDAnimatedImage` protocol. We will call `initWithData:scale:` to create the instance (or `initWithAnimatedCoder:sclae` when using progressive download) . If the instance create failed, fallback to normal `UIImage/NSImage`. This can be used to improve animated images rendering performance (especially memory usage on big animated images) with `SDAnimatedImageView` (Class). */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextAnimatedImageClass; diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index 5f15bc0b..1a2d21b7 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -61,7 +61,13 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun // enough, other can be test with InitWithData } -- (void)test04AnimatedImagePreloadFrames { +- (void)test04AnimatedImageImageNamed { + SDAnimatedImage *image = [SDAnimatedImage imageNamed:@"TestImage.gif" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil]; + expect(image).notTo.beNil(); + expect([image.animatedImageData isEqualToData:[self testGIFData]]).beTruthy(); +} + +- (void)test05AnimatedImagePreloadFrames { NSData *validData = [self testGIFData]; SDAnimatedImage *image = [SDAnimatedImage imageWithData:validData]; @@ -76,7 +82,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun expect(frame).notTo.beNil(); } -- (void)test05AnimatedImageViewSetImage { +- (void)test06AnimatedImageViewSetImage { SDAnimatedImageView *imageView = [SDAnimatedImageView new]; UIImage *image = [UIImage imageWithData:[self testJPEGData]]; imageView.image = image; @@ -84,7 +90,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun expect(imageView.currentFrame).beNil(); // current frame } -- (void)test06AnimatedImageViewSetAnimatedImage { +- (void)test07AnimatedImageViewSetAnimatedImage { SDAnimatedImageView *imageView = [SDAnimatedImageView new]; SDAnimatedImage *image = [SDAnimatedImage imageWithData:[self testAnimatedWebPData]]; imageView.image = image; @@ -92,7 +98,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun expect(imageView.currentFrame).notTo.beNil(); // current frame } -- (void)test07AnimatedImageViewRendering { +- (void)test08AnimatedImageViewRendering { XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView rendering"]; SDAnimatedImageView *imageView = [[SDAnimatedImageView alloc] init]; [self.window addSubview:imageView]; @@ -126,7 +132,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun [self waitForExpectationsWithCommonTimeout]; } -- (void)test08AnimatedImageViewSetProgressiveAnimatedImage { +- (void)test09AnimatedImageViewSetProgressiveAnimatedImage { NSData *gifData = [self testGIFData]; SDWebImageGIFCoder *progressiveCoder = [[SDWebImageGIFCoder alloc] initIncremental]; // simulate progressive decode, pass partial data @@ -153,7 +159,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun expect(isProgressive).equal(NO); } -- (void)test09AnimatedImageViewCategory { +- (void)test10AnimatedImageViewCategory { XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"]; SDAnimatedImageView *imageView = [SDAnimatedImageView new]; NSURL *testURL = [NSURL URLWithString:kTestWebPURL]; @@ -166,7 +172,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun [self waitForExpectationsWithCommonTimeout]; } -- (void)test10AnimatedImageViewCategoryProgressive { +- (void)test11AnimatedImageViewCategoryProgressive { XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"]; SDAnimatedImageView *imageView = [SDAnimatedImageView new]; NSURL *testURL = [NSURL URLWithString:kTestGIFURL]; From d49d7f7c0a620ee61fdbea862742355a95ea25f4 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 3 Mar 2018 17:08:57 +0800 Subject: [PATCH 067/361] Add the removal and status method for animated image preloading. Update the comments --- SDWebImage/SDAnimatedImage.h | 26 +++++++++++++-------- SDWebImage/SDAnimatedImage.m | 44 +++++++++++++----------------------- 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h index 629f2d18..006ee14f 100644 --- a/SDWebImage/SDAnimatedImage.h +++ b/SDWebImage/SDAnimatedImage.h @@ -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 diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index 2d78779e..9ffb2b92 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -199,8 +199,8 @@ static NSArray *SDBundlePreferredScales() { @property (nonatomic, strong) id coder; @property (nonatomic, assign, readwrite) SDImageFormat animatedImageFormat; -@property (atomic, copy) NSArray *preloadAnimatedImageFrames; -@property (nonatomic, assign) BOOL animatedImageFramesPreloaded; +@property (atomic, copy) NSArray *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() @@ -363,7 +348,7 @@ static NSArray *SDBundlePreferredScales() { #pragma mark - Preload - (void)preloadAllFrames { - if (!self.animatedImageFramesPreloaded) { + if (!self.isAllFramesLoaded) { NSMutableArray *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]; From a6d61c409d44e7dd2de611c0a28432edecb5bde8 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 9 Mar 2018 18:28:52 +0800 Subject: [PATCH 068/361] Fix compile issue and test --- SDWebImage/UIImage+Transform.m | 12 ++++++------ Tests/Tests/SDAnimatedImageTest.m | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index f1c9f513..81dc1728 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -303,7 +303,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation]; #else - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale]; + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; #endif CGImageRelease(imageRef); return image; @@ -381,7 +381,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH UIImage *img = [UIImage imageWithCGImage:imgRef scale:self.scale orientation:self.imageOrientation]; #else - UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale]; + UIImage *img = [[UIImage alloc] initWithCGImage:imgRef size:NSZeroSize]; #endif CGImageRelease(imgRef); CGContextRelease(context); @@ -417,7 +417,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH UIImage *img = [UIImage imageWithCGImage:imgRef scale:self.scale orientation:self.imageOrientation]; #else - UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale]; + UIImage *img = [[UIImage alloc] initWithCGImage:imgRef size:NSZeroSize]; #endif CGImageRelease(imgRef); return img; @@ -434,7 +434,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH return [UIImage imageWithCGImage:self.CGImage scale:self.scale orientation:self.imageOrientation]; #else - return [[UIImage alloc] initWithCGImage:self.CGImage scale:self.scale]; + return [[UIImage alloc] initWithCGImage:self.CGImage size:NSZeroSize]; #endif } @@ -651,7 +651,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH UIImage *outputImage = [UIImage imageWithCGImage:effectCGImage scale:self.scale orientation:self.imageOrientation]; #else - UIImage *outputImage = [[UIImage alloc] initWithCGImage:effectCGImage scale:self.scale]; + UIImage *outputImage = [[UIImage alloc] initWithCGImage:effectCGImage size:NSZeroSize]; #endif CGImageRelease(effectCGImage); @@ -676,7 +676,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation]; #else - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale]; + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; #endif CGImageRelease(imageRef); diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index 1a2d21b7..b3127a24 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -74,8 +74,8 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun // Preload all frames [image preloadAllFrames]; - NSArray *preloadAnimatedImageFrames = [image valueForKey:@"preloadAnimatedImageFrames"]; - expect(preloadAnimatedImageFrames.count).equal(kTestGIFFrameCount); + NSArray *loadedAnimatedImageFrames = [image valueForKey:@"loadedAnimatedImageFrames"]; // Access the internal property, only for test and may be changed in the future + expect(loadedAnimatedImageFrames.count).equal(kTestGIFFrameCount); // Test one frame UIImage *frame = [image animatedImageFrameAtIndex:0]; From 82e3779426876e8e8b23b4c98b2c72ddeafb93fe Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 29 Mar 2018 02:24:48 +0800 Subject: [PATCH 069/361] Fix the macOS animated image rendering issue by using the correct layer --- SDWebImage/SDAnimatedImageView.m | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index 69b80a5f..05ffb75d 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -13,6 +13,7 @@ #import "UIImage+WebCache.h" #import "NSImage+Additions.h" #import +#import #if SD_MAC #import @@ -142,12 +143,18 @@ dispatch_semaphore_signal(self->_lock); #else @property (nonatomic, strong) CADisplayLink *displayLink; #endif +// Layer-backed NSImageView use a subview of `NSImageViewContainerView` to do actual layer rendering. We use this layer instead of `self.layer` during animated image rendering. +#if SD_MAC +@property (nonatomic, strong, readonly) CALayer *imageViewLayer; +#endif @end @implementation SDAnimatedImageView #if SD_UIKIT @dynamic animationRepeatCount; +#else +@dynamic imageViewLayer; #endif #pragma mark - Initializers @@ -396,6 +403,13 @@ dispatch_semaphore_signal(self->_lock); } #endif +#if SD_MAC +- (CALayer *)imageViewLayer { + NSView *imageView = objc_getAssociatedObject(self, NSSelectorFromString(@"_imageView")); + return imageView.layer; +} +#endif + #pragma mark - Life Cycle - (void)dealloc @@ -776,7 +790,6 @@ dispatch_semaphore_signal(self->_lock); #pragma mark - CALayerDelegate (Informal) #pragma mark Providing the Layer's Content -#if SD_UIKIT - (void)displayLayer:(CALayer *)layer { if (_currentFrame) { @@ -784,19 +797,12 @@ dispatch_semaphore_signal(self->_lock); layer.contents = (__bridge id)_currentFrame.CGImage; } } -#endif #if SD_MAC -- (BOOL)wantsUpdateLayer -{ - return YES; -} - - (void)updateLayer { if (_currentFrame) { - self.layer.contentsScale = self.animatedImageScale; - self.layer.contents = (__bridge id)_currentFrame.CGImage; + [self displayLayer:self.imageViewLayer]; } else { [super updateLayer]; } From f0f23a76f1fff000a84ac370b2dc5c6b02d542fa Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 29 Mar 2018 02:41:34 +0800 Subject: [PATCH 070/361] Update the comments --- SDWebImage/SDAnimatedImageView.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/SDAnimatedImageView.h b/SDWebImage/SDAnimatedImageView.h index 28748d19..fe824216 100644 --- a/SDWebImage/SDAnimatedImageView.h +++ b/SDWebImage/SDAnimatedImageView.h @@ -14,7 +14,7 @@ /** A drop-in replacement for UIImageView/NSImageView, you can use this for animated image rendering. - Call `setImage:` with a `UIImage` will start animated image rendering. Call with a UIImage(NSImage) will back to normal UIImageView(NSImageView) rendering + Call `setImage:` with `UIImage(NSImage)` which conform to `SDAnimatedImage` protocol will start animated image rendering. Call with normal UIImage(NSImage) will back to normal UIImageView(NSImageView) rendering For UIKit: use `-startAnimating`, `-stopAnimating` to control animating For AppKit: use `-setAnimates:` to control animating. This view is layer-backed. */ From 16d39e49827b667d132f376bb53be44c21314a85 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 29 Mar 2018 02:50:05 +0800 Subject: [PATCH 071/361] Remove the unused NSImageView imageScale and alignment override --- SDWebImage/SDAnimatedImageView.m | 52 -------------------------------- 1 file changed, 52 deletions(-) diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index 05ffb75d..6492e327 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -535,58 +535,6 @@ dispatch_semaphore_signal(self->_lock); return intrinsicContentSize; } -#if SD_MAC -#pragma mark - NSImageView Method Overrides -- (void)setImageScaling:(NSImageScaling)imageScaling { - [super setImageScaling:imageScaling]; - [self updateLayerContentsPlacement]; -} - -- (void)setImageAlignment:(NSImageAlignment)imageAlignment { - [super setImageAlignment:imageAlignment]; - [self updateLayerContentsPlacement]; -} - -- (void)updateLayerContentsPlacement { - NSImageScaling scale = self.imageScaling; - NSViewLayerContentsPlacement contentsPlacement = NSViewLayerContentsPlacementScaleAxesIndependently; - switch (scale) { - case NSImageScaleProportionallyDown: - contentsPlacement = NSViewLayerContentsPlacementScaleProportionallyToFit; break; - case NSImageScaleAxesIndependently: - contentsPlacement = NSViewLayerContentsPlacementScaleAxesIndependently; break; - case NSImageScaleProportionallyUpOrDown: - contentsPlacement = NSViewLayerContentsPlacementScaleProportionallyToFill; break; - case NSImageScaleNone: { - NSImageAlignment alignment = self.imageAlignment; - switch (alignment) { - case NSImageAlignCenter: - contentsPlacement = NSViewLayerContentsPlacementCenter; break; - case NSImageAlignTop: - contentsPlacement = NSViewLayerContentsPlacementTop; break; - case NSImageAlignTopLeft: - contentsPlacement = NSViewLayerContentsPlacementTopLeft; break; - case NSImageAlignTopRight: - contentsPlacement = NSViewLayerContentsPlacementTopRight; break; - case NSImageAlignLeft: - contentsPlacement = NSViewLayerContentsPlacementLeft; break; - case NSImageAlignBottom: - contentsPlacement = NSViewLayerContentsPlacementBottom; break; - case NSImageAlignBottomLeft: - contentsPlacement = NSViewLayerContentsPlacementBottomLeft; break; - case NSImageAlignBottomRight: - contentsPlacement = NSViewLayerContentsPlacementBottomRight; break; - case NSImageAlignRight: - contentsPlacement = NSViewLayerContentsPlacementRight; break; - } - break; - } - } - self.layerContentsPlacement = contentsPlacement; -} -#endif - - #pragma mark - UIImageView Method Overrides #pragma mark Image Data From 920d61f47e48d80621ccb5310c719248d362409b Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 29 Mar 2018 03:36:21 +0800 Subject: [PATCH 072/361] Separate the image class and coder class's protocol. Make this two more modular --- SDWebImage/SDAnimatedImage.h | 60 +++++----------------- SDWebImage/SDAnimatedImage.m | 22 +------- SDWebImage/SDWebImageCoder.h | 48 ++++++++++++++++- SDWebImage/SDWebImageDefine.h | 2 +- SDWebImage/SDWebImageDownloaderOperation.m | 2 +- 5 files changed, 61 insertions(+), 73 deletions(-) diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h index 006ee14f..968b47e9 100644 --- a/SDWebImage/SDAnimatedImage.h +++ b/SDWebImage/SDAnimatedImage.h @@ -7,51 +7,25 @@ */ #import "SDWebImageCompat.h" -#import "NSData+ImageContentType.h" +#import "SDWebImageCoder.h" -@protocol SDWebImageAnimatedCoder; -@protocol SDAnimatedImage + +/** + This is the protocol for SDAnimatedImage class only but not for SDWebImageAnimatedCoder. If you want to provide a custom animated image class with full advanced function, you can conform to this instead of the base protocol. + */ +@protocol SDAnimatedImage @required /** - The original animated image data for current image. If current image is not an animated format, return nil. - We may use this method to grab back the original image data if need, such as NSCoding or compare. + 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. However, for progressive image decoding, we will use this instead. - @return The animated image data + @param animatedCoder An animated coder which conform `SDWebImageAnimatedCoder` protocol + @param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property. + @return An initialized object */ -- (nullable NSData *)animatedImageData; +- (nullable instancetype)initWithAnimatedCoder:(nonnull id)animatedCoder scale:(CGFloat)scale; -/** - Total animated frame count. - It the frame count is less than 1, then the methods below will be ignored. - - @return Total animated frame count. - */ -- (NSUInteger)animatedImageFrameCount; -/** - Animation loop count, 0 means infinite looping. - - @return Animation loop count - */ -- (NSUInteger)animatedImageLoopCount; -/** - Returns the frame image from a specified index. - @note The index maybe randomly if one image was set to different imageViews, keep it re-entrant. (It's not recommend to store the images into array because it's memory consuming) - - @param index Frame index (zero based). - @return Frame's image - */ -- (nullable UIImage *)animatedImageFrameAtIndex:(NSUInteger)index; -/** - Returns the frames's duration from a specified index. - @note The index maybe randomly if one image was set to different imageViews, keep it re-entrant. (It's recommend to store the durations into array because it's not memory-consuming) - - @param index Frame index (zero based). - @return Frame's duration - */ -- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index; - -// These methods are for SDAnimatedImage class only but not for SDWebImageAnimatedCoder. @optional /** Pre-load all animated image frame into memory. Then later frame image request can directly return the frame for index without decoding. @@ -71,16 +45,6 @@ */ - (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. - - @param animatedCoder An animated coder which conform `SDWebImageAnimatedCoder` protocol - @param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property. - @return An initialized object - */ -- (nullable instancetype)initWithAnimatedCoder:(nonnull id)animatedCoder scale:(CGFloat)scale; - @end @interface SDAnimatedImage : UIImage diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index 9ffb2b92..a6d4b8bf 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -282,9 +282,6 @@ static NSArray *SDBundlePreferredScales() { if (!data || data.length == 0) { return nil; } - if (scale <= 0) { - scale = 1; - } data = [data copy]; // avoid mutable data id animatedCoder = nil; for (idcoder in [SDWebImageCodersManager sharedManager].coders) { @@ -298,24 +295,7 @@ static NSArray *SDBundlePreferredScales() { if (!animatedCoder) { return nil; } - UIImage *image = [animatedCoder animatedImageFrameAtIndex:0]; - if (!image) { - return nil; - } -#if SD_MAC - self = [super initWithCGImage:image.CGImage size:NSZeroSize]; -#else - self = [super initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; -#endif - if (self) { - _coder = animatedCoder; -#if SD_MAC - _scale = scale; -#endif - SDImageFormat format = [NSData sd_imageFormatForImageData:data]; - _animatedImageFormat = format; - } - return self; + return [self initWithAnimatedCoder:animatedCoder scale:scale]; } - (instancetype)initWithAnimatedCoder:(id)animatedCoder scale:(CGFloat)scale { diff --git a/SDWebImage/SDWebImageCoder.h b/SDWebImage/SDWebImageCoder.h index 0dcaf874..1afe6757 100644 --- a/SDWebImage/SDWebImageCoder.h +++ b/SDWebImage/SDWebImageCoder.h @@ -9,7 +9,6 @@ #import #import "SDWebImageCompat.h" #import "NSData+ImageContentType.h" -#import "SDAnimatedImage.h" typedef NSString * SDWebImageCoderOption NS_STRING_ENUM; typedef NSDictionary SDWebImageCoderOptions; @@ -118,11 +117,56 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp @end +/** + This is the animated image protocol to provide the basic function for animated image rendering. It's adopted by `SDAnimatedImage` and `SDWebImageAnimatedCoder` + */ +@protocol SDAnimatedImageProvider + +@required +/** + The original animated image data for current image. If current image is not an animated format, return nil. + We may use this method to grab back the original image data if need, such as NSCoding or compare. + + @return The animated image data + */ +- (nullable NSData *)animatedImageData; + +/** + Total animated frame count. + It the frame count is less than 1, then the methods below will be ignored. + + @return Total animated frame count. + */ +- (NSUInteger)animatedImageFrameCount; +/** + Animation loop count, 0 means infinite looping. + + @return Animation loop count + */ +- (NSUInteger)animatedImageLoopCount; +/** + Returns the frame image from a specified index. + @note The index maybe randomly if one image was set to different imageViews, keep it re-entrant. (It's not recommend to store the images into array because it's memory consuming) + + @param index Frame index (zero based). + @return Frame's image + */ +- (nullable UIImage *)animatedImageFrameAtIndex:(NSUInteger)index; +/** + Returns the frames's duration from a specified index. + @note The index maybe randomly if one image was set to different imageViews, keep it re-entrant. (It's recommend to store the durations into array because it's not memory-consuming) + + @param index Frame index (zero based). + @return Frame's duration + */ +- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index; + +@end /** This is the animated image coder protocol for custom animated image class like `SDAnimatedImage`. Through it inherit from `SDWebImageCoder`. We currentlly only use the method `canDecodeFromData:` to detect the proper coder for specify animated image format. */ -@protocol SDWebImageAnimatedCoder +@protocol SDWebImageAnimatedCoder @required /** diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index ae5dfd0d..604e0cd9 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -50,7 +50,7 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustom FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustomTransformer; /** - A Class object which the instance is a `UIImage/NSImage` subclass and adopt `SDAnimatedImage` protocol. We will call `initWithData:scale:` to create the instance (or `initWithAnimatedCoder:sclae` when using progressive download) . If the instance create failed, fallback to normal `UIImage/NSImage`. + A Class object which the instance is a `UIImage/NSImage` subclass and adopt `SDAnimatedImage` protocol. We will call `initWithData:scale:` to create the instance (or `initWithAnimatedCoder:scale` when using progressive download) . If the instance create failed, fallback to normal `UIImage/NSImage`. This can be used to improve animated images rendering performance (especially memory usage on big animated images) with `SDAnimatedImageView` (Class). */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextAnimatedImageClass; diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index d0f36d7c..0d755b44 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -365,7 +365,7 @@ didReceiveResponse:(NSURLResponse *)response UIImage *image; if ([self.context valueForKey:SDWebImageContextAnimatedImageClass]) { Class animatedImageClass = [self.context valueForKey:SDWebImageContextAnimatedImageClass]; - if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)] && [animatedImageClass instancesRespondToSelector:@selector(initWithAnimatedCoder:scale:)] && [self.progressiveCoder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { + if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)] && [self.progressiveCoder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { CGFloat scale = SDImageScaleForKey(self.cacheKey); image = [[animatedImageClass alloc] initWithAnimatedCoder:(id)self.progressiveCoder scale:scale]; } From 082c5af565c4b6ab25f3fc259f22f480902be7dd Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 29 Mar 2018 17:45:56 +0800 Subject: [PATCH 073/361] Add APNG coder to support static PNG & APNG rendering. Also update macOS's SDAnimatedImageRep --- .../SDWebImage Demo/MasterViewController.m | 1 + SDWebImage.xcodeproj/project.pbxproj | 28 ++ SDWebImage/SDAnimatedImageRep.m | 47 +++ SDWebImage/SDWebImageAPNGCoder.h | 19 + SDWebImage/SDWebImageAPNGCoder.m | 380 ++++++++++++++++++ SDWebImage/SDWebImageCodersManager.m | 3 +- WebImage/SDWebImage.h | 1 + 7 files changed, 478 insertions(+), 1 deletion(-) create mode 100644 SDWebImage/SDWebImageAPNGCoder.h create mode 100644 SDWebImage/SDWebImageAPNGCoder.m diff --git a/Examples/SDWebImage Demo/MasterViewController.m b/Examples/SDWebImage Demo/MasterViewController.m index 669a71c4..a5ba345d 100644 --- a/Examples/SDWebImage Demo/MasterViewController.m +++ b/Examples/SDWebImage Demo/MasterViewController.m @@ -63,6 +63,7 @@ @"http://www.httpwatch.com/httpgallery/authentication/authenticatedimage/default.aspx?0.35786508303135633", // requires HTTP auth, used to demo the NTLM auth @"http://assets.sbnation.com/assets/2512203/dogflops.gif", @"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif", + @"https://raw.githubusercontent.com/onevcat/APNGKit/master/TestImages/APNG-cube.apng", @"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp", @"http://www.ioncannon.net/wp-content/uploads/2011/06/test9.webp", @"http://littlesvr.ca/apng/images/SteamEngine.webp", diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 15054747..8700c40f 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -376,6 +376,18 @@ 325312D1200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; }; 325312D2200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; }; 325312D3200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; }; + 327054D4206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 327054D5206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 327054D6206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 327054D7206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 327054D8206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 327054D9206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 327054DA206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; + 327054DB206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; + 327054DC206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; + 327054DD206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; + 327054DE206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; + 327054DF206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; 3290FA041FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3290FA051FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3290FA061FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1449,6 +1461,8 @@ 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDefine.m; sourceTree = ""; }; 325312C6200F09910046BF1E /* SDWebImageTransition.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTransition.h; sourceTree = ""; }; 325312C7200F09910046BF1E /* SDWebImageTransition.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransition.m; sourceTree = ""; }; + 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageAPNGCoder.h; sourceTree = ""; }; + 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageAPNGCoder.m; sourceTree = ""; }; 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageFrame.h; sourceTree = ""; }; 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageFrame.m; sourceTree = ""; }; 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImage+WebCache.h"; path = "SDWebImage/UIImage+WebCache.h"; sourceTree = ""; }; @@ -1703,6 +1717,8 @@ 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */, 321E60AE1F38E90100405457 /* SDWebImageWebPCoder.h */, 321E60AF1F38E90100405457 /* SDWebImageWebPCoder.m */, + 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */, + 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */, 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */, 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */, 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */, @@ -2161,6 +2177,7 @@ 80377DCC1F2F66A700F89830 /* lossless_common.h in Headers */, 321E60971F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, 43A918671D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, + 327054D7206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, 431739571CDFC8B70008FEB9 /* encode.h in Headers */, 00733A6F1BC4880E00A5A117 /* UIImage+WebP.h in Headers */, 323F8B711F38EF770092B609 /* delta_palettization_enc.h in Headers */, @@ -2241,6 +2258,7 @@ 80377C1D1F2F666300F89830 /* huffman_encode_utils.h in Headers */, 321E60B11F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 80377E9A1F2F66D400F89830 /* common_dec.h in Headers */, + 327054D5206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, 80377C231F2F666300F89830 /* quant_levels_utils.h in Headers */, 321E60BF1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 80377EA61F2F66D400F89830 /* webpi_dec.h in Headers */, @@ -2396,6 +2414,7 @@ 323F8BDC1F38EF770092B609 /* vp8i_enc.h in Headers */, 80377ED21F2F66D500F89830 /* vp8i_dec.h in Headers */, 32484779201775F600AF9E5A /* SDAnimatedImage.h in Headers */, + 327054D8206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, 43A918681D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2419,6 +2438,7 @@ 80377C8D1F2F666400F89830 /* random_utils.h in Headers */, 4397D2C31D0DDD8C00BB2784 /* SDWebImageManager.h in Headers */, 323F8B551F38EF770092B609 /* backward_references_enc.h in Headers */, + 327054D9206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, 80377C811F2F666400F89830 /* endian_inl_utils.h in Headers */, 321E60991F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, 323F8B8B1F38EF770092B609 /* histogram_enc.h in Headers */, @@ -2508,6 +2528,7 @@ 80377D871F2F66A700F89830 /* lossless_common.h in Headers */, 321E60961F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, 4A2CAE041AB4BB5400B6BC39 /* SDWebImage.h in Headers */, + 327054D6206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, 431739511CDFC8B70008FEB9 /* format_constants.h in Headers */, 43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 323F8B701F38EF770092B609 /* delta_palettization_enc.h in Headers */, @@ -2628,6 +2649,7 @@ 80377C0B1F2F665300F89830 /* random_utils.h in Headers */, 80377E921F2F66D000F89830 /* vp8i_dec.h in Headers */, 5376131F155AD0D5005750A4 /* UIButton+WebCache.h in Headers */, + 327054D4206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, 53761320155AD0D5005750A4 /* UIImageView+WebCache.h in Headers */, 530E49E816464C25002868E7 /* SDWebImageOperation.h in Headers */, 32484769201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, @@ -2951,6 +2973,7 @@ 323F8B991F38EF770092B609 /* near_lossless_enc.c in Sources */, 80377DE81F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */, 80377EC31F2F66D500F89830 /* vp8l_dec.c in Sources */, + 327054DD206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */, 325312D1200F09910046BF1E /* SDWebImageTransition.m in Sources */, 321E609D1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */, 323F8B9F1F38EF770092B609 /* picture_csp_enc.c in Sources */, @@ -3151,6 +3174,7 @@ 80377C221F2F666300F89830 /* quant_levels_utils.c in Sources */, 80377D2E1F2F66A700F89830 /* dec_mips32.c in Sources */, 323F8BD31F38EF770092B609 /* tree_enc.c in Sources */, + 327054DB206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */, 80377D5C1F2F66A700F89830 /* upsampling_sse2.c in Sources */, 323F8BC71F38EF770092B609 /* syntax_enc.c in Sources */, 80377D321F2F66A700F89830 /* dec_sse41.c in Sources */, @@ -3304,6 +3328,7 @@ 80377E301F2F66A800F89830 /* yuv.c in Sources */, 43A9186F1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, 323F8BD61F38EF770092B609 /* tree_enc.c in Sources */, + 327054DE206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */, 80377DFD1F2F66A800F89830 /* dec_mips32.c in Sources */, 323F8BCA1F38EF770092B609 /* syntax_enc.c in Sources */, 80377E2B1F2F66A800F89830 /* upsampling_sse2.c in Sources */, @@ -3451,6 +3476,7 @@ 4397D2A11D0DDD8C00BB2784 /* SDWebImageManager.m in Sources */, 323F8BCB1F38EF770092B609 /* syntax_enc.c in Sources */, 321E60AD1F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */, + 327054DF206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */, 80377E341F2F66A800F89830 /* alpha_processing_sse2.c in Sources */, 4397D2A61D0DDD8C00BB2784 /* SDWebImageCompat.m in Sources */, 80377E6F1F2F66A800F89830 /* upsampling_neon.c in Sources */, @@ -3570,6 +3596,7 @@ 323F8B981F38EF770092B609 /* near_lossless_enc.c in Sources */, 80377D6F1F2F66A700F89830 /* cost.c in Sources */, 80377EB31F2F66D400F89830 /* vp8l_dec.c in Sources */, + 327054DC206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */, 325312D0200F09910046BF1E /* SDWebImageTransition.m in Sources */, 321E609C1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */, 323F8B9E1F38EF770092B609 /* picture_csp_enc.c in Sources */, @@ -3727,6 +3754,7 @@ 80377CE51F2F66A100F89830 /* cost.c in Sources */, 80377E931F2F66D000F89830 /* vp8l_dec.c in Sources */, 321E609A1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */, + 327054DA206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */, 325312CE200F09910046BF1E /* SDWebImageTransition.m in Sources */, 323F8B9C1F38EF770092B609 /* picture_csp_enc.c in Sources */, 80377D141F2F66A100F89830 /* upsampling_mips_dsp_r2.c in Sources */, diff --git a/SDWebImage/SDAnimatedImageRep.m b/SDWebImage/SDAnimatedImageRep.m index f0907d5c..b922716a 100644 --- a/SDWebImage/SDAnimatedImageRep.m +++ b/SDWebImage/SDAnimatedImageRep.m @@ -11,6 +11,7 @@ #if SD_MAC #import "SDWebImageGIFCoder.h" +#import "SDWebImageAPNGCoder.h" @interface SDWebImageGIFCoder () @@ -18,6 +19,13 @@ @end +@interface SDWebImageAPNGCoder () + +- (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source; +- (NSUInteger)sd_imageLoopCountWithSource:(CGImageSourceRef)source; + +@end + @interface SDAnimatedImageRep () @property (nonatomic, assign, readonly, nullable) CGImageSourceRef imageSource; @@ -26,6 +34,43 @@ @implementation SDAnimatedImageRep +// `NSBitmapImageRep`'s `imageRepWithData:` is not designed initlizer ++ (instancetype)imageRepWithData:(NSData *)data { + SDAnimatedImageRep *imageRep = [[SDAnimatedImageRep alloc] initWithData:data]; + return imageRep; +} + +// We should override init method for `NSBitmapImageRep` to do initlize about animated image format +- (instancetype)initWithData:(NSData *)data { + self = [super initWithData:data]; + if (self) { + CGImageSourceRef imageSource = self.imageSource; + if (!imageSource) { + return self; + } + NSUInteger frameCount = CGImageSourceGetCount(imageSource); + if (frameCount <= 1) { + return self; + } + CFStringRef type = CGImageSourceGetType(imageSource); + if (!type) { + return self; + } + if (CFStringCompare(type, kUTTypeGIF, 0) == kCFCompareEqualTo) { + // GIF + // Do nothing because NSBitmapImageRep support it + } else if (CFStringCompare(type, kUTTypePNG, 0) == kCFCompareEqualTo) { + // APNG + // Do initilize about frame count, current frame/duration and loop count + [self setProperty:NSImageFrameCount withValue:@(frameCount)]; + [self setProperty:NSImageCurrentFrame withValue:@(0)]; + NSUInteger loopCount = [[SDWebImageAPNGCoder sharedCoder] sd_imageLoopCountWithSource:imageSource]; + [self setProperty:NSImageLoopCount withValue:@(loopCount)]; + } + } + return self; +} + // `NSBitmapImageRep` will use `kCGImagePropertyGIFDelayTime` whenever you call `setProperty:withValue:` with `NSImageCurrentFrame` to change the current frame. We override it and use the actual `kCGImagePropertyGIFUnclampedDelayTime` if need. - (void)setProperty:(NSBitmapImageRepPropertyKey)property withValue:(id)value { [super setProperty:property withValue:value]; @@ -45,6 +90,8 @@ // Through we currently process GIF only, in the 5.x we support APNG so we keep the extensibility if (CFStringCompare(type, kUTTypeGIF, 0) == kCFCompareEqualTo) { frameDuration = [[SDWebImageGIFCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource]; + } else if (CFStringCompare(type, kUTTypePNG, 0) == kCFCompareEqualTo) { + frameDuration = [[SDWebImageAPNGCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource]; } if (!frameDuration) { return; diff --git a/SDWebImage/SDWebImageAPNGCoder.h b/SDWebImage/SDWebImageAPNGCoder.h new file mode 100644 index 00000000..8abf9fd7 --- /dev/null +++ b/SDWebImage/SDWebImageAPNGCoder.h @@ -0,0 +1,19 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCoder.h" + +/** + Built in coder using ImageIO that supports APNG encoding/decoding + */ +@interface SDWebImageAPNGCoder : NSObject + +@property (nonatomic, class, readonly, nonnull) SDWebImageAPNGCoder *sharedCoder; + +@end diff --git a/SDWebImage/SDWebImageAPNGCoder.m b/SDWebImage/SDWebImageAPNGCoder.m new file mode 100644 index 00000000..cbf261a9 --- /dev/null +++ b/SDWebImage/SDWebImageAPNGCoder.m @@ -0,0 +1,380 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageAPNGCoder.h" +#import +#import "NSData+ImageContentType.h" +#import "UIImage+WebCache.h" +#import "NSImage+Additions.h" +#import "SDWebImageCoderHelper.h" +#import "SDAnimatedImageRep.h" + +// iOS 8 Image/IO framework binary does not contains these APNG contants, so we define them. Thanks Apple :) +#if (__IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0) +const CFStringRef kCGImagePropertyAPNGLoopCount = (__bridge CFStringRef)@"LoopCount"; +const CFStringRef kCGImagePropertyAPNGDelayTime = (__bridge CFStringRef)@"DelayTime"; +const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef)@"UnclampedDelayTime"; +#endif + +@interface SDAPNGCoderFrame : NSObject + +@property (nonatomic, assign) NSUInteger index; // Frame index (zero based) +@property (nonatomic, assign) NSTimeInterval duration; // Frame duration in seconds + +@end + +@implementation SDAPNGCoderFrame +@end + +@implementation SDWebImageAPNGCoder { + size_t _width, _height; +#if SD_UIKIT || SD_WATCH + UIImageOrientation _orientation; +#endif + CGImageSourceRef _imageSource; + NSData *_imageData; + NSUInteger _loopCount; + NSUInteger _frameCount; + NSArray *_frames; + BOOL _finished; +} + +- (void)dealloc +{ + if (_imageSource) { + CFRelease(_imageSource); + _imageSource = NULL; + } +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif +} + +- (void)didReceiveMemoryWarning:(NSNotification *)notification +{ + if (_imageSource) { + for (size_t i = 0; i < _frameCount; i++) { + CGImageSourceRemoveCacheAtIndex(_imageSource, i); + } + } +} + ++ (instancetype)sharedCoder { + static SDWebImageAPNGCoder *coder; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + coder = [[SDWebImageAPNGCoder alloc] init]; + }); + return coder; +} + +#pragma mark - Decode +- (BOOL)canDecodeFromData:(nullable NSData *)data { + return ([NSData sd_imageFormatForImageData:data] == SDImageFormatPNG); +} + +- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { + if (!data) { + return nil; + } + +#if SD_MAC + SDAnimatedImageRep *imageRep = [[SDAnimatedImageRep alloc] initWithData:data]; + NSImage *animatedImage = [[NSImage alloc] initWithSize:imageRep.size]; + [animatedImage addRepresentation:imageRep]; + return animatedImage; +#else + + CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); + if (!source) { + return nil; + } + size_t count = CGImageSourceGetCount(source); + + UIImage *animatedImage; + + if (count <= 1) { + animatedImage = [[UIImage alloc] initWithData:data]; + } else { + NSMutableArray *frames = [NSMutableArray array]; + + for (size_t i = 0; i < count; i++) { + CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, i, NULL); + if (!imageRef) { + continue; + } + + float duration = [self sd_frameDurationAtIndex:i source:source]; + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef]; + CGImageRelease(imageRef); + + SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:image duration:duration]; + [frames addObject:frame]; + } + + NSUInteger loopCount = [self sd_imageLoopCountWithSource:source]; + + animatedImage = [SDWebImageCoderHelper animatedImageWithFrames:frames]; + animatedImage.sd_imageLoopCount = loopCount; + } + + CFRelease(source); + + return animatedImage; +#endif +} + +- (NSUInteger)sd_imageLoopCountWithSource:(CGImageSourceRef)source { + NSUInteger loopCount = 0; + NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(source, nil); + NSDictionary *pngProperties = [imageProperties valueForKey:(__bridge_transfer NSString *)kCGImagePropertyPNGDictionary]; + if (pngProperties) { + NSNumber *apngLoopCount = [pngProperties valueForKey:(__bridge_transfer NSString *)kCGImagePropertyAPNGLoopCount]; + if (apngLoopCount != nil) { + loopCount = apngLoopCount.unsignedIntegerValue; + } + } + return loopCount; +} + +- (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source { + float frameDuration = 0.1f; + CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil); + NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties; + NSDictionary *pngProperties = frameProperties[(NSString *)kCGImagePropertyPNGDictionary]; + + NSNumber *delayTimeUnclampedProp = pngProperties[(__bridge_transfer NSString *)kCGImagePropertyAPNGUnclampedDelayTime]; + if (delayTimeUnclampedProp != nil) { + frameDuration = [delayTimeUnclampedProp floatValue]; + } else { + NSNumber *delayTimeProp = pngProperties[(__bridge_transfer NSString *)kCGImagePropertyAPNGDelayTime]; + if (delayTimeProp != nil) { + frameDuration = [delayTimeProp floatValue]; + } + } + + if (frameDuration < 0.011f) { + frameDuration = 0.100f; + } + + CFRelease(cfFrameProperties); + return frameDuration; +} + +#pragma mark - Encode +- (BOOL)canEncodeToFormat:(SDImageFormat)format { + return (format == SDImageFormatPNG); +} + +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDWebImageCoderOptions *)options { + if (!image) { + return nil; + } + + if (format != SDImageFormatPNG) { + return nil; + } + + NSMutableData *imageData = [NSMutableData data]; + CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatPNG]; + NSArray *frames = [SDWebImageCoderHelper framesFromAnimatedImage:image]; + + // Create an image destination. APNG does not support EXIF image orientation + CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, frames.count, NULL); + if (!imageDestination) { + // Handle failure. + return nil; + } + if (frames.count == 0) { + // for static single PNG images + CGImageDestinationAddImage(imageDestination, image.CGImage, nil); + } else { + // for animated APNG images + NSUInteger loopCount = image.sd_imageLoopCount; + NSDictionary *pngProperties = @{(__bridge_transfer NSString *)kCGImagePropertyPNGDictionary: @{(__bridge_transfer NSString *)kCGImagePropertyAPNGLoopCount : @(loopCount)}}; + CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)pngProperties); + + for (size_t i = 0; i < frames.count; i++) { + SDWebImageFrame *frame = frames[i]; + float frameDuration = frame.duration; + CGImageRef frameImageRef = frame.image.CGImage; + NSDictionary *frameProperties = @{(__bridge_transfer NSString *)kCGImagePropertyPNGDictionary : @{(__bridge_transfer NSString *)kCGImagePropertyAPNGDelayTime : @(frameDuration)}}; + CGImageDestinationAddImage(imageDestination, frameImageRef, (__bridge CFDictionaryRef)frameProperties); + } + } + // Finalize the destination. + if (CGImageDestinationFinalize(imageDestination) == NO) { + // Handle failure. + imageData = nil; + } + + CFRelease(imageDestination); + + return [imageData copy]; +} + +#pragma mark - Progressive Decode + +- (BOOL)canIncrementalDecodeFromData:(NSData *)data { + return ([NSData sd_imageFormatForImageData:data] == SDImageFormatPNG); +} + +- (instancetype)initIncremental { + self = [super init]; + if (self) { + _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)}); +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif + } + return self; +} + +- (void)updateIncrementalData:(NSData *)data finished:(BOOL)finished { + if (_finished) { + return; + } + _imageData = data; + _finished = finished; + + // The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/ + // Thanks to the author @Nyx0uf + + // Update the data source, we must pass ALL the data, not just the new bytes + CGImageSourceUpdateData(_imageSource, (__bridge CFDataRef)data, finished); + + if (_width + _height == 0) { + CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(_imageSource, 0, NULL); + if (properties) { + CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight); + if (val) CFNumberGetValue(val, kCFNumberLongType, &_height); + val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth); + if (val) CFNumberGetValue(val, kCFNumberLongType, &_width); + CFRelease(properties); + } + } + + // For animated image progressive decoding because the frame count and duration may be changed. + [self scanAndCheckFramesValidWithImageSource:_imageSource]; +} + +- (UIImage *)incrementalDecodedImageWithOptions:(SDWebImageCoderOptions *)options { + UIImage *image; + + if (_width + _height > 0) { + // Create the image + CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL); + + if (partialImageRef) { +#if SD_UIKIT || SD_WATCH + image = [[UIImage alloc] initWithCGImage:partialImageRef]; +#elif SD_MAC + image = [[UIImage alloc] initWithCGImage:partialImageRef size:NSZeroSize]; +#endif + CGImageRelease(partialImageRef); + } + } + + return image; +} + +#pragma mark - SDWebImageAnimatedCoder +- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data { + if (!data) { + return nil; + } + self = [super init]; + if (self) { + // use Image/IO cache because it's already keep a balance between CPU & memory + CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)}); + if (!imageSource) { + return nil; + } + BOOL framesValid = [self scanAndCheckFramesValidWithImageSource:imageSource]; + if (!framesValid) { + CFRelease(imageSource); + return nil; + } + _imageSource = imageSource; + _imageData = data; +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif + } + return self; +} + +- (BOOL)scanAndCheckFramesValidWithImageSource:(CGImageSourceRef)imageSource +{ + if (!imageSource) { + return NO; + } + NSUInteger frameCount = CGImageSourceGetCount(imageSource); + NSUInteger loopCount = [self sd_imageLoopCountWithSource:imageSource]; + NSMutableArray *frames = [NSMutableArray array]; + + for (size_t i = 0; i < frameCount; i++) { + SDAPNGCoderFrame *frame = [[SDAPNGCoderFrame alloc] init]; + frame.index = i; + frame.duration = [self sd_frameDurationAtIndex:i source:imageSource]; + [frames addObject:frame]; + } + + _frameCount = frameCount; + _loopCount = loopCount; + _frames = [frames copy]; + + return YES; +} + +- (NSData *)animatedImageData +{ + return _imageData; +} + +- (NSUInteger)animatedImageLoopCount +{ + return _loopCount; +} + +- (NSUInteger)animatedImageFrameCount +{ + return _frameCount; +} + +- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index +{ + if (index >= _frameCount) { + return 0; + } + return _frames[index].duration; +} + +- (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index +{ + CGImageRef imageRef = CGImageSourceCreateImageAtIndex(_imageSource, index, NULL); + if (!imageRef) { + return nil; + } + // Image/IO create CGImage does not decompressed, so we do this because this is called background queue, this can avoid main queue block when rendering(especially when one more imageViews use the same image instance) + CGImageRef newImageRef = [SDWebImageCoderHelper imageRefCreateDecoded:imageRef]; + if (!newImageRef) { + newImageRef = imageRef; + } else { + CGImageRelease(imageRef); + } +#if SD_MAC + UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef size:NSZeroSize]; +#else + UIImage *image = [UIImage imageWithCGImage:newImageRef]; +#endif + CGImageRelease(newImageRef); + return image; +} + +@end diff --git a/SDWebImage/SDWebImageCodersManager.m b/SDWebImage/SDWebImageCodersManager.m index 253cd092..7c755533 100644 --- a/SDWebImage/SDWebImageCodersManager.m +++ b/SDWebImage/SDWebImageCodersManager.m @@ -9,6 +9,7 @@ #import "SDWebImageCodersManager.h" #import "SDWebImageImageIOCoder.h" #import "SDWebImageGIFCoder.h" +#import "SDWebImageAPNGCoder.h" #ifdef SD_WEBP #import "SDWebImageWebPCoder.h" #endif @@ -36,7 +37,7 @@ - (instancetype)init { if (self = [super init]) { // initialize with default coders - _mutableCoders = [@[[SDWebImageImageIOCoder sharedCoder], [SDWebImageGIFCoder sharedCoder]] mutableCopy]; + _mutableCoders = [@[[SDWebImageImageIOCoder sharedCoder], [SDWebImageGIFCoder sharedCoder], [SDWebImageAPNGCoder sharedCoder]] mutableCopy]; #ifdef SD_WEBP [_mutableCoders addObject:[SDWebImageWebPCoder sharedCoder]]; #endif diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index ece0791a..0e1acf88 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -49,6 +49,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import +#import #import #import #import From 5da5ec92fbd7dea60456ba31f9cab00692234fc6 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 29 Mar 2018 17:59:32 +0800 Subject: [PATCH 074/361] Add the test for APNG coder --- .../SDWebImage Tests.xcodeproj/project.pbxproj | 10 ++++++++-- Tests/Tests/Images/TestImageAnimated.apng | Bin 0 -> 193101 bytes Tests/Tests/SDWebImageDecoderTests.m | 8 ++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 Tests/Tests/Images/TestImageAnimated.apng diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 06c14c7a..4209b95d 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -16,6 +16,9 @@ 3254C32120641077008D1022 /* SDWebImageTransformerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */; }; 3264FF2F205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */; }; 3264FF30205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */; }; + 327054E2206CEFF3006EA328 /* TestImageAnimated.apng in Resources */ = {isa = PBXBuildFile; fileRef = 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */; }; + 327054E3206CEFF3006EA328 /* TestImageAnimated.apng in Resources */ = {isa = PBXBuildFile; fileRef = 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */; }; + 32A571562037DB2D002EDAAE /* SDAnimatedImageTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */; }; 32B99E8B203AF8690017FD66 /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */; }; 32B99E9B203B2EDD0017FD66 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; }; 32B99E9C203B2EE40017FD66 /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */; }; @@ -34,7 +37,6 @@ 32B99EAC203B36650017FD66 /* SDWebImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */; }; 32B99EAD203B36690017FD66 /* SDWebImagePrefetcherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */; }; 32B99EAE203B366C0017FD66 /* SDWebCacheCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */; }; - 32A571562037DB2D002EDAAE /* SDAnimatedImageTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */; }; 32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */; }; 37D122881EC48B5E00D98CEB /* SDMockFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */; }; 433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */; }; @@ -64,10 +66,11 @@ 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransformerTests.m; sourceTree = ""; }; 3264FF2D205D42CB00F6BD48 /* SDWebImageTestTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestTransformer.h; sourceTree = ""; }; 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestTransformer.m; sourceTree = ""; }; + 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageAnimated.apng; sourceTree = ""; }; + 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImageTest.m; sourceTree = ""; }; 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDCategoriesTests.m; sourceTree = ""; }; 32B99E92203B2DF90017FD66 /* Tests Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 32B99E96203B2DF90017FD66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImageTest.m; sourceTree = ""; }; 32E6F0301F3A1B4700A945E6 /* SDWebImageTestDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestDecoder.h; sourceTree = ""; }; 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestDecoder.m; sourceTree = ""; }; 37D122861EC48B5E00D98CEB /* SDMockFileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDMockFileManager.h; sourceTree = ""; }; @@ -137,6 +140,7 @@ 433BBBB81D7EF8260086B6E9 /* TestImage.png */, 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */, 321259EB1F39E3240096FE0E /* TestImageStatic.webp */, + 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */, ); path = Images; sourceTree = ""; @@ -300,6 +304,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 327054E3206CEFF3006EA328 /* TestImageAnimated.apng in Resources */, 32B99EA3203B31360017FD66 /* TestImage.gif in Resources */, 32B99EA4203B31360017FD66 /* TestImage.jpg in Resources */, 32B99EA6203B31360017FD66 /* TestImage.png in Resources */, @@ -321,6 +326,7 @@ 321259EC1F39E3240096FE0E /* TestImageStatic.webp in Resources */, DA248D61195472AA00390AB0 /* InfoPlist.strings in Resources */, 433BBBB91D7EF8260086B6E9 /* TestImage.png in Resources */, + 327054E2206CEFF3006EA328 /* TestImageAnimated.apng in Resources */, 433BBBBB1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Tests/Tests/Images/TestImageAnimated.apng b/Tests/Tests/Images/TestImageAnimated.apng new file mode 100644 index 0000000000000000000000000000000000000000..54f73736abc493ab22cd46338bcdc2d0b418b355 GIT binary patch literal 193101 zcmZ7d1#sNJ(y)#0t~q9AjF}l?$IK8jJ7#8Pj+rTDW@e0;V`gTKA!f#Z^PY2VeRWmU zQjgR-YH8-_mS(i!3g09UKjD1>004+mlA=lg08kLDU&2Cw*Wx#Fn&1trfsu+VcxwU{ zz;X^Z1K8+?f~<;|F9t4P7~u~9@bU2>Uo^V`0E~exI$%oyfG7Z94*)O*7u6xZ0fB%9 zSb#VrpdZ#1yvG$1PyxFD0I-5UAVv_t3=)tC3kZh+*&}{J1Of740hzE=*o2@!6gp}) zsq8Vagm$_7DR%29Vk!Wmk+)R(AQ6|iaAX6oPwqEtLZR>~4sGYJKMJV@<@sFFI^h9q zvieL?8Ym(lE>&|09x(}eW)2}K$>d&cm!D5hPnu|$(iDKx(^Dih$hEaK5(zB>Gyu7* zp)MQ(rHUo3wzG+vnzXzMDkGzXqdNitF}FvCFA9K35`xVkirpb$cyu(_-5t^x)fpBc zC_HjzcFu%~zNNJdMg#{^169?;CNn!*TN=`m0gxCLhGY#{R8s0C2<+(U%KiDXw|~$z zFf=JOT~f!ivbr{$27oIqL9D9TP*G7=--s;Dl$&1|laMsj*~zA;i=@lo$RimN6K_TE zna3EC+dCzL5Pqmk<1R6kpt68{A+*aKKh1R zcsnq2+Mq3IKH7Yef?!CBvuXEPu7C0R^ZrsXhO*{BwqQ%BqrO$5!s+wK9LmNvyy|iP zeIx;B>W`}roeDJdFzlfRYuq@-{#)_yTUnC_s?e>pTNAC*6_26BOsqYskNh8+e>}Wg zH*Zc8*AVQ*x|ls`)ZJf-a)6Az4+m8{kqy`=?;dRKoH$6&xcXnV?)Y*@38DqE+Wy{~ zK&K|GiFJk5uHhe3a--ig$tMa_hvIINZ54L?HiNAgz`^bDT_b(_0@0Cz9CFb+KPm_B zyt5a2nX!bH+A$6|a*Q7^b8|9h>GIlLqFQ=0tKl(vri92GStvXgm^3>Y&eW7X(QT~o zSP}=ex8QCkT^RMGv=GY`{TN3pb)m5wsUg>p)_YC&fBWz|XS!@cdpgs_4K`s(sK&la z{9=aH+HH(|-i_Z~ctx;tdCir?JR|eA&ON+S1m!~IhjDpnO|kU(teD|WsgamsbJ9V1>dQLUeo zvnxKRxfiWxBmhO}0;{~}93lv&>Fp?3L7rtS$YD0RHIT-Wy7qhH&5W3c-zgBr3{O$M zI*<(~2xnUoGz1`=wXL4^?AoG+DqE0_emgPf+_v0p@N|Ipz*JspE3@Dm9d_f`lmEd0 z&EDCs*z@7zg9#K5!nlX-#Q?a4NhZvGNiLBI3RLSiK!06ZUr4As2QjNC&KM$) zU?h;fhEN}4oKZtf7FRAauAuG+%|yvJqt_DOBMrid4m6YJmFWxQ(~4vAVbZ@8!=+t~ zB!h^A)+H5#tXU1UL*jT2am>`iCq@Ft2Pamd>2)Ramow8;|Kv(TK+3r& z_qu<4PP$uteKdv#PEqs6@O(3-@JELcfsJt{F+p`K^NS6mJqI-d_-r}uO^2y|R6!7Q z@yF0&!VZq}o4#KJ<+{FUxtsD+m@+`Oj;rpWaWQzbn)tUQT7D;E6XR=%W$}}ts*3?i z{%Y&n>DK>>0WE23)orfjXfprg-o)T!*3-g!&-vG~HJSlr+$OX1)mL(Yk{>x_{#McN>2F>)L|lLp-8Cd6`rf z(CP*l$wdGRfFoI1lQY3X35Wo%tL-)haa(5^?r{M503L+G*d-bB*&oGye#^V3QFA8G z*FGyJ4}@V{hr^ZfFK$!PUqI`2u0>RjDf`Q7De>1AZ17y_vq+8gG+f8@x%&CthVcg4%& z;(>sCn}@uKTuaAU4c0?_roM8-VU(B?&;C;0Z2ojLwum<6v?*UFVpz6dI3<^CWQP9N z0B0WngWGd`OQ)x|B+l+av3r(ST|B3A1Lg!qiYV+1y7<)F;=W-6U?P%b#Jkxos85TCS>Re; z0uvjpTb$JzE#dG>Eu4LV`-AN9Y{Fh*7L|9yXPTd!tX3=RQ(rGs>#za!`+4XR?m;*f z=cy3qz5i^Yw;S;7)Giw?J5D>V@8zvLrEBM<#PbHyphl9E^<2H{Z$z1f$cK3ObO+@x z)k(L*KQbECKA{Bc7+uwn+?Hjr^Lu#qoZ4-#-8gv{wbKTi+x-Mw&X=e@LZZ zCF>?Yg?(NggmT3aAaa67J66!VUmMZYFXnxkW%bwV-Y{X9$_nQ764AQ}n~^lki;CWf zlOj~6ObJpIohM(b%KxWHu=jgFR@|jqdLq+X33P|#0WY;GFB58N>S(Yt`&UX0X-fr?w-xBK=(F2f-+;!yk z+SeAMwh$MQQ{PQP)nB%bOSdgUA^d-}%OoJ{&a<%YZF2;nnmrcB$8a@NJej2;wEFV5 zyH(TV3a4&Tpr(lpV+~`GFEv97L0n+W9VoeR@XE8DF|q`?3A{Y9Zzc zLyq9n^dgsbvAdns*icSmnQ6Wn0()C3+CMC9+*X7Z#7JC*hDp5@9~)uR z8e2zyI`a;*Wd1a^0a+^QSjIzm5%U2DxIyAgxI#s=aS}t|SvUD<)7h7Th7`CZ(QH?w zkJBrUIec}f_|TTkhj|EG)=JF)6gN`uJDaD^RK zWGG-X0cirCb1)*xU}La4QxFCD#@27IKyBKiZye$VnOAGaOOGS7JYc>8pqhEB?iW3} ze}gIFP1xrn)BT&w!TIAM@a|(T5=Y=K!{6qfivg|4{n3V;s1uP=~ zYUXY*19QYs>Gez69St-ri1RsMow-Mf{n_n48<` zcId4X$}iDMsI9}b)4X&6mRMpBq4nbQok6~IezT&}=<=Slq^t!8HwJ-)NW(>vyb2y@ zs&ZX~D7DUy!-bvxP$c2fUq?;rg$HD=?vH zXKpnjj;RNUFj1~*_a*)T$rn<$jw;o5j$}%M=~|IL%6NjbG$Ae0#dW`8?7`4_-G^i; z)RF@PJ#w=DlJR46|HdCp2E3RAt1#$4+dI zCk}G3s1ii49HmWW%Y+RPjWcDrYK%*{G)`Ld9hN9$aJ*E`j=8-#4I#`uQZI&LK^wp+>LuMLFqG(=$jB3tb*wCU6s{a2GoU26DINqQ2=iPrIAT zXlD&C+vC6;cG2<@3R)mhCgHFtm<}uO;k47M+owpT9tyw)`}#Q>E4fhHZAEwXOg24e zYs{}MR2nywFt<09Fn%oeI%ZGhd(~O#k|I{;i}$)P#!B{-X`+|kQx&5b5T|APu{}a3 zheLB=trGq|1C>N4%HVhph6`R`BJDzsw_!8IUTWuBc>rB9kn5foCYjq1wkzwLh zRQi^QdbSO+!O}h|o#WM5E#u{1aYTqW!C{8$aX`{4f@79~{X?3ACE|}qk~Mw8Uw7Kp zi1k-{<4~{jipba2_h><|YS|W-7~y}a z2KcyK($B!@vpdJMVCGjx7mY2l*Lg_)ec0ZD3ysvkHd?mK_8?0^-JVm73^MRL!5_DO z(1#Om3SHk^EN#gQy@EZ2L#zC~bk~~yNoP1UPTP+$Ay?y(I?rSE6y4XZTb?^>FdegQ z;R}~2W5(#aVGUcx?O~$sPr?hE9VN6!g(y(_uU3NI4iY2Ta)S`D}f|YW@^!u>d~! zO1$D*4yVBaoc^F?)FQDP?{T8srF!iaq<>T-3;mtEW!hz)YWH-W$M|{vh;D$WX_lT? zZ49cYJtkRdO1>PzpX1ieR`mP!swRaql%Vj+j?>sZO;mjO;=GbRY8M2ayp(d1-bQ|=6rcla)& z5V4zcPUz_dC5y(4oDs1@pWeST%5e4y^!Tm-43^{N`q9~%T+T}UV{_T%huSyZ$uh^k z#&^Pq13WZStpB7e(C-9p1=D!DT*!zIB4I<~Y3OPqv6~d>VpLl#tZ^eW{~7~VmG-YH z)wxFaT7sSS+xx+nE9dv_Hp^n>`0l=~a&CRn8g8s z5t815uYo2#gUqnA7rn6N0H6MV;O}qu>1{UZgoH(G(Yn;qS&5Reiax^Rk&G^WQC%vx zvd?atBnf7gXluI#wmOM z#mECT$>DOXk&}Up3BXGro)<5>7bI)6%Gnu>?&BQZo z+G&i;jqRt6hTXFm?vWvoNRw`RO`B`_yz^=9?j(8{#%5DM`eQsOrPG2x@aP+e&|yvC z?;n+#p$&!fQ<)-axPhTyn6bk91Q$+$=3n^bTz&a%kS}sDmmA(Ixcel_(&kiNk`%@8 z@m|W|zn6kPHN|nt3Jh{ml>aXJbV;YM(OZaop8?$d;U)27($+O_V(^ebL3IO^O!Qmj zV(!!c%NZ1|BNK+k?LH(Pe-bI6eAe<)zq?X;f1~CtS71ciJ}pk%%eN1PhhX3;Q`xcwOHC}yf|xGZWaKdo4{MOo zw0r7?&-?7CeK=^lUR9FN@VQ(YK?uFgny^MAq6(zYgeWg~G;zmGh>%LdMWsOiYq$ot`s`tNeG2(?hk=57B4H_1 zD!v@A+Udqd;Wkd_=1+}D7nwJa->=l-;4Uq;w~gJiADr^XXM7iIDgpXVUyirDk@xwU z&d6?xPp3q(#cAFj_#L9ALM~_;5f9YG+*s(x`G;hh-&lEPr#`qp1@^Lk?G-Ylsl>|< zmHjLJ+Dypih}v-W_4V-G>Rg!jQ^ z)95$YJ=s6Te@4co{I#*u-V+Q_+M&D7qs$j;A$h?;?(ubkfc)y&hM+Yz57|EQS7msv z(Pn>NCn*0I&|l!rUcw6R;w`8A#GuSZ4P2}8NBfonD~_*`hvLi-YB&drIC z=J*T0Sy^F2_ztZ|jH|5&W;hXGbcvghTL#O!)x+KS{mN`k{0Fo}uh zv7_|PCN%+Hdj&R)3Rt7IQv`F%g%seZj)No>#KdKezZ{0lQYSf@jIl-Ob-Z1l;1QF+ zZcY_1ou1OTl@!7`|CA~uz>xltEobbg;}cVaB!`>!L^@8;t+4b6=-jw6_>TCuw<2yi zISv>hxlAt3hZBe+mW%B*KO=fby39CM&3)$WezL&9C@6o~{KqrH0WQDMS#e2gPjn~= zV2JS+3bk#KuR*DY+|F9oxRWU`HrfzW@{_n*$G?kzeRF)(JTGV4$GVSF*7K1MCq9az zs0`I6AUy(d)N{TK9 zRygeWi9T(rOfOh>!AvM#clJ z+wAhkGb>_+m5zVdllD&83A~wUhV^e~i$Hbi*5hoU**-Q8vJu3`c9n16(D$Iv=2L2a z4Z(!PJ#XBVa%Ix6`Gxg+;*X@-{}rPy@<$BLnKR&!l3GQG(#%?DPe;$L{`CI%7Yf$s zZup>-DU;^Bei_L-htn0OLo~@UD+4QIk;Z_2Y(Bc6m*v!$FOS3OLG9^ivYSdUX#PQ? z8L~f36>APIy|Io_9-SH|OFi2a8O@GzsBCNG+V;HE8{MvlDSEs{u$>sCys8)<9S9 z`3MSXIv@ucxD0wdxO%!z0m9<&uGDb<^bRs|d_&UnXKu~})fnEh#XPg>d^ZB!0!d+^ zC(@Kw-!ah|lI%C?`R!<9o*kbb4?v;=zp^F*5682E>i6f}_RYeFJ}K|tAX>eKEO0>g zF!wGkz(W2&CP=@eGf;y|F_Z)O4#E$^3|$g3u;$XVwZK zoXB}38YYHrF%z)5xzBv&U$QWVtq>5<5yKSy_6UccHAG4APHW!j4~V;@i8 zCBE-LAcW47w4QY5o+Rf5VL#I14NNYp*rwO>M|zB|W!(TnJ}<^>`zxziuQkwf6f;-1 znN7Q7>vvczj_t}KGhQxm@b{4PmJffu=BR3^s6afE=4IJv!Y1SoYmSm(DO{WM+V8vB zp>aKub%{o1CQzz@zaT;^Eq_-!&zLwoXAFV;+>U&;v0*y5UfmM;loUG|T5`6*L#*#7 z>7(lPU~WE9p0CTt*s@knuVXM$?Rg*mk4CtPzdRfJ z3ldfOY*tKM&NOf_0U@e1_ch&pd6S#B+s9wha({fF|6bf>0^P z{5)(QO(;0D9T5SHb&)t6O`jjdHoYKFq@pv^%uBlzzTd!-Bxn_r|GpQ0eTD?@-b~kD z-Yl(tf<}>&doaJvdp6|ZeLy5hNI#!Zxtbve)7t`&l^qjBb9p=TUTLFs6M-F@`-Zz=8U1M%*XI@lrJ;>^5fGPjKG%Ns0kHHYJ{B6owP0y)@GEnr(6 z1bil6h6RosAgf)>wkHNpzuyKwQJCHZkgUuj$+Kr?;+s_RfE@sA>Kq%AQiAq#8R7!S zIu*0s;~9ApS?JBoj^oc>HfJapsG=8iqQwk0>>tJ5RX<@^Xz~ZUnw5zgLb8B8w&I}= zKD65$1Ux7+ctJ!aNm%_pgCm_SE$YO_=P!A(d4RB{O-4p@%`XXd`j^Dpu*5H+O_)z8 zQX6&;VJDHsF#A5W;2L~fV@tav#|uh?z^%aaGOKNE$LUMr`vW?xu=(pTLq>A-Ga2P! zA`K}-(6${_SwlTc=fR>C9a%f#6+XWpdDBGs>MdsX!#Zyc1i0kV?nk_UU3QU!?F0%d zEathH_$!wlnlhLP_Pkpv?ysET{#z7SZ$D)yXChlbzv86=dl%k{v*^fu&~U)C>!u6# z3C)Jn;^-ujyv7dR)D~QBch7OH?2>Gx@I8V>k+MlavDWm7=XjVj17D3z2H9T)pZG&K zFXn%(lX0QER{u=qIx^UT3%($kj&iy7zYMflUlqXjda2i$PR zHDJ%bf<2!Xvt=Bc8yyU_c^|F;_W_w^5B8MZht^J$oc&Hvp_EUHfK1#;S_~lQ2D~Wg(@ER@s61wdAXcf48<(^4CBOXurWvwQg^L18O;V+gA+i zm8(*vpD);ga6gM!6YV#BTfcR=^ETjV73vvez&P>^2NTB#%)u6f>P`j!Ay1LETn1H2` z<`#`7a~OvsmC<(>vPWWm9|}xwo)(%3Ykh25LF-pf7NN38Y^g?RMg&Oa-|X;!za zKW+sDdDN=J>+`fxDZ|Js`Wo#atZTarq%V!Fj>5Q7Bj0zE%Vq$n1DmmcB zK9O2DVR4?kxkZdZbja_%K6t-EBx65uN$&bJX*z&9^+R;HC)#-?gm|R7jr)pItNX)` zw6dI#Ei7rAV2vV{Uevj)6hTxkS5bQ%$wF4Q0RQ=b8h#cUk{l?VfbRUdM8&JAa*!NV%liH`YbAQG^6hOs55=kn7tp8*~c@DCMyYuHM9-olLQZXcO}tD@In`@{o^So%g7BwAmTuw<>I+`9FFO!%ke=s z3_!<#keq2z84AEO$92^#8%bSRa~QJ}K(!pOoyO=b@v91Ao1G0U-V2fhsI_9T%5A9v z0yq>z(4hA0#K8;7rN*Rn=3AZD){#$sgHly0$3GM;zbA3IAP~ ziPH#WdR;u-yTKz48|SP)o>}ag3q%D8*=_?NC5xD+$&eE;Z~&ISglK3C1f@8x?TMC} z0&x8ewT9Az2ZMTO-htN-Jev;Rp<2NJ{SUW)9|ipbN*FBva1;FxZsF1lyI|bp{)-!= zJFse|HxfevWBBSqTW9MF|LITF;__c5p+k_-ZIB>cM-(COH#$O+jECFAaRiPdAM$sa}9GjR{beU-McbVISsYMx?R7zeD6+M=#P3st?->}?>yV~e_YhGqll5ae`kE& z`vOa*Siv%Pa3Xozo^r}aZJ->gty%t7?9ieU(RAR4FW@Dq4>XQw}Bpmk4uzY`s`l#&pX}%ub!} zeBN_3fc#qDSNkTe^s!tKT;ZcpMFBZE%Dlaig@%RA54V%mNJIj~tuCJ%GBI28BYT%N zDq4~9MXm!J#0B01_))9#1UQNC{S%S>=ApN6_6v|#<5H~JdZcKj^8L*H8s-BjenU?_ zXWO&5=AuMRz~J4e!3J+~3VdzHLv05~1N%3WQOscur*AVKy{LI?@&V`r@jnbJY~^^u zjgfwLdX3_(+{Lp6?dxhQ7%WY_;_?X3anYSeh_IGeU>MM`K3&3pX3NK3N7K49G>Yk~ zj{N|oByiFb&j;kKB}uLLhSvlE*icknqHU+Ci{Ra-B-_Hi6}@u};SR zzy3B67)BjomAHW_4|DNMA{)v&^@Qxc++jJvWtG9gD+FsBb(!wM&%wX!J^xg@nzT%2?MF2!$c1 z8O3am2}urvO2+8}v=D--oLj=l#{klLWx0xv<&pp=B~vtgVd`7%+|`K^gjF2KtC$vW=Qw*k2|rKD8A|2Ppkfmd4E0G9jntN@uZ` zYzP#m1fjr^mOw`B0j|#R_{EVT^%+oBNb}FoN8r93w8rJyi6TV^R_Jn#7iOG51(w%? zM_qfozU9yF-omkqivdwFV1qIdYK*^OuWA5mjL3up4wF3#0Gvppo#DcI6A0AjYRWCR z!p1!DEAJ3JW4xNtHgnxz%>IWT6j)aSiwIc2U+RIk|CjBm4vnV3_(}g4KWK2ao1con z|G#V(+|;C-(!RQJ`p$;Ol8QnVs)N7}ABQ4;&32?c(b-Or<)JFbbW7pJ!@y;oKGr$Yc;-Gxe$k)4CYUPs+jWS2w-V1gE#f_ z9M@(l?B$Fudc8@tNp#|5xBW8d)NT4rc5S^RUuqz!p~L&>BpY{^oJw6zM`4fP^kog3 zIBh4h;Y8{F8@p4;g5}-$kL>sb9Pc5iI(xOddnbrxZ{D$7niUeCm~oAo3$==)iweO@ zz{TR+oadn9kfHw2&05A?#eW%6#^C>AzpLlfbznqCQa30mNB)$N%xqg{H(yL8z=pfKBTRfYH&V9O z87ew1a7%8Yh@UGSH{;^Ulx)&yR+{T|V*JbGO7wm?uI(iGtTvRmgh9@YMDE|xEmRhO z+b6MnwT8FgsAieKa=g8)ASfd{e)_Hh6ybuFYd?8QeMK(md*_|vuTqn2mRyCBpx1}e zI2ztHl;ez&ri#P_=IB)dp|KWPJ0X@$rvjr0<);E!d6Dkui>>+V3Nr9CLi~M9sPgFx zlZ#)@Tt!^yNyuqGd1X;1=R&|}M$XvlR4DeE-IL9-e_uf~he`)|^*4RTZY~teC5W+; zoI7k&lRr>^2hyoqp8`;#K6g@P5;yL)sz}aYz@Tv0lh6KO|I?;2r}Wjo#61QT5mtY@ zEsVn;sS*9#jvFxq?D!|Z&^APYui+g$B#A=6Nqi5vP-&EXRFG8s5bSXz;iU6#DE}}b zUG?0CQSwv!GizQBYU{6`QG0&KLkudAd2w&`uuZs$!kv)-hQfrGa0Q`h18b=?3}P(q zG7bMo%MtO#d{!-s;o%2C4%Z!T)CSzJQ&7gYwLooQSZ?beO-q8f+Umj$Qv|;GDzMg_ zr}Xf&ya-8R3K~r*OKt&FnhNj}dFEXz zFh{_Q{f|8uu>OxdQLy}DPxwFV`9L>@{XeM>)*aY1KV?ZEfiiq$2QNc0QdI5Qvf-!I zfSWlWg+z*S$$<@n5V)QY>GT_7!1qUoH{TfvedF0=^-vDXfauJ*JoESY8?3*IXWWD-XXEv!X4^ z#e4=1e9kt{@D_ZmwnGvJTO%~~h>DhIifp|uzCFN^&S*B#VA0xdGOj7VuLA3sGD^;) zSXiz60)AH~Pl0W#G$%e|5TRLFS>HPuJcL|-98{XRDBkU6A%Z$Q9ohs=z3HSek)FIO z8pgKLVT5N9u)X@xu^x{$4i?rZnH_o%>HfU^#lKs>VYo3SMHo!Kgd)8W{g!`+;ZCAb zUCoo_v``6G;mC+-#a}!3R5p{Rf#G^HD&?&jsjHD8Hbs=@kRT%SRWDeyD~5}H@3RC- z=PvUWyHiphus%GU=Eoj2*IB&yL@~=#k0SY|Zfzn$m4(u>; zX$}#EyTE4x%NMSY{zD^mr?D>YQwe;T0us&Fi09RmHgLb zs{Rj%pknH9A7OtD)>T;RpF_3IwPFWpZw-YlSR8yy^ch{qJvXhs zCyayW6B?-RGbneWE=b>Fz{&r!*fqxYN{dNC*fVlS90rkH$ts-11T!=OAxIrqKwTmm zgF}R%N>8qWa&-J84vW9WS9uZ(W&G5-qTuwPCdf=Df*n5_8Y_`%>IWT99aMN zq9+EHfA|Ug2fudaK3Fh*-2Y8|pTJL^OH;N4V*g(Bs+NCNj(wMNTlX_HV;2sf&%7gAcTVqDjTuP;s?#ih?o`leSyKrt)xUp^FSA2hg$fMLAOxO{I zO9z_dEf{I3%1h|Lr=N7HJ#|VXJf6~kUaj1m{@z(h^_Mh`={25dl|Od*B?CeZ&IPq8 z(YAOn>8M|58i<~G=7M|3gTGD*A}fW4f0S{4Sr$Vl*k{+?ouLc}fT%kO(cKboKtU}l z;{O$9*2}^haOe>yI0H>$qfg3$rm!cp0Uh4iGg}EFDsW&`?tlowd7Ne@x9_5XJ&hjh zfgt(&4Wn1wKS)?h{oX&&Na8}gS8TS6m>~t0`<#kszA@^|gPjPsDZ#V}4Sn4Pp4T!> z1Iq1Hpw{B%EQ~p^0XVWJ0)PdH8Y)hYCW!CoeqOXED8z%ub;KnZDiu^rO_89kT&7Y* zgga{^*(Mc=LeXB8fJ~Ol2>vWALWibd9|k~soTiDjA+E~{+*1w|WKg4AOwfvA^&t1| zz{wRKBrA!R7B`Y>4_POJq#|=KtxClt5~by(5I2m1sA8qYRS@6V$&4Dv_gucDXtuZw z;3p_~Lf)+Ac@7UucLx*oKhogA`oBc?|3}*0Wr`%2H0J-3h5#mQegaGyhTx8J!Ll2x zlX8oaiQAhj7lSZa-ET^zj!^Nx4Lv} zkB?Ux)b;o?IK6H%eyu zv03iS&CuyQ5YH}Y)wcUX0T~)0=J1)2M*?EQOnIxa!hK@5(8<-%TF%=rZKAJoSvSpP znCvuiq0g3mdPQT~u+zt*OLKk$K1NKfV&Zx5;C=&_u z9Qis)nuMd0b1m(yO0lU(w)eIxnx@0Asp3JW*xT&k%f3$Gx7vJx6mB!1lv6Psu8cB% zm^0cd#zQYKngXr_g@3&=S~*%12A|$aRySyyTZ%dbKX+hRYqGqV3*m>Q)l071$DT3c z-$~#L)@q5-(nq z+c{ewvV5YCE)Yah{oWAMztQ}vND%3FdmF;u>a=!XerX33OfMn*v0KgtivB9E;d$e##S)CpUDKLSV}6QXx7^1_oJO|AvtLy5w=m55!D>fkW9A1eEWQ&I0UpjsQpY1Wo`fP4Wq8*}gXd z_ax<3IC{z+2Yf1Fkn?@!?jK|_LHkKk0FwMXFd99UbrGSI)7<8|OccQJ`)A2j(JU(< z739Rg{R@uNKJWt&lEUc|OE7x){}6`wU&187+kd%C;6J$x;q(Lir>Os5E<*x8N={9H zU*rA}_CvyrTu=48y2nY$LOynk2rQ-kB_|~B3gn(@eYhTJu5rft8lhftNo- z=$snevr(J(b5eD7$K!eE#N>0e+3iTAo`}pQRj1!(-Shs!%gp*@tH%c0%ifDI_tC7W z6jM#t$4gE05IN_`VYV&1trKioN1NVUY*;}PfL`r(FY`wdzTlDdRond((uv4vPF3E? zw7{v>vUREzNB8N_sI2^jZQ2OS+D-di!(c?0t*xz^+k+L>tdeVV7SR7{ZsaQzD(~%L8l%0vda$R>JNqqVw`g6bP z4MkAu05^16B=;73s7B|^jKl;Ux~cQe*sWNpeY8F!-D_^CH8qe~TU=a;yC%tuq#z! zk0@1JVDxUxc1*YXpe`#>Q!B8%P5#>}UdLN_TBWV4W=`4>L-&pR6`w6))c9;jte@b` z_@ymW_5cDj$#|Y0qgty%^rV`YwuZeLs%bSY&Tg>Ni>Mo#P_Q z_mnB=m|IeXev#%fvRefh@>(vmCOq|qcv{9wv7#U4KZZBG^=nL!vrl26LKWS&&FdLd zTZL&=dW-50{N1KoQ&pu|ad^n{c+`Kw!_6rGy~7B~{biu`6U+;(q5S`Fiz*`nqHl2G zm7oNR$q2$N0V27Epfs`1P*Wt~u{=^lAPa*{@ zv6#yhSG-lo6-0*ewv~T6YX1okYApX=m8=sV#!rB^ z_y?0N2XM*cd9*a2ne~?VE?o?;$|Cot4OJTr?}|Y{+l;YYdT>(D(5lcyi{8&Y$9L zkNAAXlRX^s2_#YhDPQ?#JB(3c#hrWcW3Gp5jv}9ebUknXz?IT+{}ek*apw9cIMSpE zZggzJnPEExz2}m{lFkmchVK2AnEJR?PPPh)W0d)mbMX!hUl6fw5?PW+l&w{yWl7t* z8I)i?UiS7o3(lYcfWlTB8-zl=Sd6-s(1oGTCkW{v?+2^_gq&fzbO5TboQG1FVoC+^ zY%%6SQj1~pTBZ0R+J3;nq=||UNqeU(Hw5*QHy&J6UU6Jx$bsX=JhBeZUA@lXE}h{= zuYR&D+83FI0z;Egb5}w?oX*MlKz`3>Pu6s?8o9ikh&SlZ;_N#ORP1G!@0PxKjy3_A z)Ws$ZVe)u?U4lowX&3;_uR96Nh>!JkkIlD3tx1UO7h`(wq2fN91G_1`sc}{#STl1Z_2W1BSYYc|~Uk`Havi@_2|0Kq8}MGej1{B<+^)zZkoMk7ZPbFAiT%w%zPNF@uW%j{K<~J^-_iJ(Sug@Z$(0*q6jvsG zq>&`#6to_v1)#nEZJ}vGZf@2}2Pe*hmj3tn zbNyR>Z(KvOijbppUwl1U{rHi;zCf7+4glU?oJU4NQmLn1r9nFclAijaUOWJyb3rP+vD`)vP;nMB zm^B!ql9WQJL8k~t{eUL<3*wN}FOfhkON$lLBFMs~c@0GI8IINXV4csc;Xf5{_GE+} z%sWQ-9Je5(tQgvqQU1`UCE|)@gBC}vG$Jw35Iqi9va1u@`T?z@-#@!&DjWMdN_q+xrQi)u?{N+mP}$(}v=#DOv?uSY!ne;fbsgfhZck z-cHZn&(>^hVvz+glwE6e%U|MbzQpS4tl8GsG<_EO1@#)N-aH!l>-f6gYi(a6lJt_- zyH@O;3DpN;y~nP3_$=SD)(IgqsBb%~iiOZp-wYH|hv8atw}(822h7Li4jfZ|j(>d| zKr1#A#3^K}t>L;rvGnzE{J4eFXLd&#s+&)|aPv>h(5v3Cx!)M013>qG{n`!f9MwSI~oly#9J$uJ)%Iz%4SxwhuJXmU%Es78T2MTSS_Y5MPiw6$nmU{;9}1-I?d^BdYowMA zoQf(m3ep-9MwkJYLwfQ&2BfhiiUxet${(2_GiWRu2E z5``CK0H9a2)oT8ILz=apqK&yDn|H>eOV7&rBLPiP%G}&o@>!9IOi-rp`03Adeay^> zA{~`DQjXSYUW$4kk6gtyN#OpV6J45n;y4`7=m^PbDW0Ubms+jaS$VaV0^m1-C`TA4 z4ThTYrL{9>Arb%>#|FZ~S6g)H9eM0gLZZrv?Y=g}4yuRz{cP`H?ZI-SH6tv$kAV0G z1JKsU^OC%jELKo%G+IiJVy$z~b8RSXQG1iabY!`y5I9aEj_=CT(BW6nl%Y3Vc8Syz z`#IBSc+1t0m-qqt5CTWboJn>;2{ZbO;6k~u*hzjMlyD{Oyb1Q(4R1k&IM)Bi);q;$ z8g*OSPuc9UZQC}wY}>YN+vu{*F59-%W!qI>z4_mr?EKjWE14&ER&pP#jBC!Z#=j^!1>-`pluA@?+C%^84oVqwAS zeBPE@ph6U#Ym;p&G)M^u3A-Be`?Sim4y%tH&obx;gmqF&q0=6pWj|%B&E;?1s$tUJ zp_&N)+)lfqhuuJJQ0B@5q0!b!ou^@dZeYlt!h4J)d(#}0AkTt z$ahe|gn{_#!vv;Aj0zaq;}t#&WWw?{5o&PW{fyhxQXW6rrs;BquY!irC!E5vqm1+{ zWuc=WbdWbT1o-WJ5&2nzM<%s;`xpN*H3kei!55D1@Hr7O_gb?JOyX~lP2+SkW6`zv zgIWZ3tO8GFw>UB$(-4H%?V?J2p)qPHg^yyQkQ5{6AAtnjG5jL}3Apzq1yTZ?ESweuj zV_mkf^Sk4n>bGr_sG>Hf)DRY8wwR!yO}+MfWcu#$qp^w7*VPQ6Y)P2o%xF1{gb1^j z?Zd@CTIa1k8zGwN{5jnEY-v^5at9JPD0%!&NORO3K1*unO#XG>mZ$!q)zTSrz1eno zIt6cUCDm`8mjK9DX(e!f<2{za(x(EN9ak^~loTtKlsFwo_!HdcqI7Os+ltW!qe64b zY5p8N?^e8rB~uz<8>%K#c$R)2I{{?CK5-$Wr~%pI>Sy(UZQl92!4BAnGkog2;rG$| z%Ax|ZKoV-hL1B1uZBAjuo$G~VpTnH4H^!HZEK3h0V*&f|eRe$~=a2xh$N7kpS>-aV$Ka?{+P908MXNt`EF`4rld!Tra}! z$iExT(?pc3K)4IY6g&>=MqjpX1k|#95CEaWqO#2oz*mQhVqGS&t)d4&lfdC-ZB2Zr zhgE?q#&+xLJ?`m!-l98$e)4EFSn@sld;$R%#m}zbA}2H-g)?T4v?!*OJHG>L?KP|f z&kwjL6%V)e+fWK_R(avc!qD{j`xmY|!jW$++cI4lUNK`En8*y!;21ymig@0(X-f^A z-c*8xXYUo7bo>|j@%sclPEtn|nJJ|XoIjkYWc}byTW7ta2If4Gf*8&^dCpX=Vs}o| znVlL76Olf|1ks++3Zl0BD52yWFq=lSOoI!q%5~tKp1Od=Jl|L~HD(K4(eOXK1S6Ozh(VRam(@y&Qpx0tqZtBP3n=_e@ zV_l;)P9`eiHZe?Xao$@2I!j{P84@bMDoguKSf1mMWg^?fg!F_=@TjEC?9f7-NB&_7 zeAvK?2JB^yM(Aa-OO}GvYBtNjfI>H0J)6IfkR35nL*Wf1!TB_p%@uqr$UtYveIT=N z!&rz=VpMP4_^_`G54=mWEyTbABCHoYh(@f=mi}1DCJ@dhlx4Ef?JocJ%rPT4!ig3| z63YE8@p&k4RW?G_C5^5GBW=rmf>s<9AaRx7=Rs6zoCpws3)CzF@|(sUJ-iMKHZCFR zEEru6;jkTH&vW?09Ie^0Im`YDci`J``H8t)629rlw`PGdWI+5UI_7^g*RP+t_hA#u_YjFG+jyb+ zK0^9ETt5DK;oU{=_PJt=_5gK(g5FEW6r+vZT@m;CBJ?8ftVchZ|VrXjdf_rjRqC73Ub_d(O zH@NSR!yWnBFa&y}TeS=J9;&=?y98?WyZt;EloJk{ZQXF|)k565hyEyRRxQls?>;tH ztF@8@68`B{16Ev>1bH76yI{T;=O^%tWvq;S1pwjTlUH9? z7#veTJzn=g@ryG~JOE7KT2#~*@<|3(H&IUy2y?U^z<7R&L;H{GD(D?fX{DCaZ>I;i zo}Iwd5J31O3mePQTsR)e%t+?3Uf=hEIwM z4mG>N0(fBMUI%(vEdYATuH5mJH~}yealPiSxOb0rOd8PXM)Z8xx5kN%vI4*WA?u)e zWB}!A#-a12;MovE-Tq-@2$TUeDml?%K9?gC%&+^)2Da6^1hC1 zeV_j7q*7`n{w1`eIHOYE}I9NOWd+O9%qxa^T6A4DE_RPF1l_515o-0yKJ>6^1i zL7=axut=t`MIpuRJ8YqBTDTy8z&V=K$3}BUI(&4geAD$y3eluXL5URTub>U_I^`F| zYwW!;Vt$JP|0RW?m~6Of&LZnE)t>;AQd}_0SV4#@u0LA%oO&vG0;e)dVzWTE<0|C$ zq4x`-C{Y-Wm5cz2F)(t+x^o;CG{L!*G7v}(p4)So+xZlda{5xdA467TEW@PfYm`a-KF071fHMCujc>vZw5 zQiJDxcMw)<#XI0nQOVLpLgcOi9(To2@|mZNsU-?kTohfe!U;t|22H?C9y6d7OV5|0 zDD#@eZ>fTY1Pv1eo7vY6X^fsNpf^&_id{J|fo%j`!hrklLi=*tk%)7+snLWjtJ<2M zl8ih2g9+lbcPzMOqSA_nmUhaG2n@=GX>>YuVx@o8z0cZpE2D0_}P z1)-g__4M(^1UI%3agcm=QhglF-{WAzahDNrZlm)Vzgw%O$%4w?WlQUpDT9d4KomJn z$_nYwOOkNKut5-xdBva-bJD5Xu0)ka(>^vfRVvjaK6+j@%7iD`IcKk-u3M5-h2sU~ z$OW6vh^N_dNGXosO0(dBqCm=yu-&@oo$-nOr~KA10;32ygBAO)ktY&5j<8Ge{zNN$ zaDZXC>_Lo~E85DqSSAu5Xuz2|nEwtAM*wdAxxc;wP|)${9UyusAyQk^AF-J)R7oWt zk`zPWst>@0L(9VHzse*IQ@=6-?EK)!bE)<>+3#!U+xt|`@9yFLFir0RATpHjSAt6a z#*nL`JXcA%?tUnb&+q>8xw@gf{dIjvHkEzH?_Q7p`wqfqcyU%ko;tsXjiY+w8F%Gw zD5?d>)D*yW+l4OyFs!b>_x70?Lqk@E&h2!WsGm}2G3t)J7W{MmHyxdtAX2}qT-|<9 z2#ZXP6)vRHYj<*TQo~nC`p>!4+hLoLVBYU_LD6Lxf2N}KQbEa9J6)%iWi`7Z2>$Qw z;kzd*JOMXa6Q#RUy*^%Oh1D_d%-s;O0r=r2;%Ug8R)bD;}an2PFQ zh9dl}4L7vZT+Ow=ZGY?keyVs@nS%lTEWdqOb?Z`6$bl-Gpd%M)wnOaRot+)MJsrMI&Z(yH#&oxPSeP*Kq*uq)1C;52APOS(C3F}^RVHrp z?zuf4Aw6*HfLAxQd)hvl@Y!t81)%=y zed7(5h7wCrP|EZ2xl{B4RuF*urPqt{l$6(&(iCqKqy5tZDnK4CQtsLrJy6i*@=EWA z7!_bk;BjAQQWM|hf$RxTHIw>fVe|B@O4jY^Ok)H@+U#xA4Nez_lrI8{Hn`^jw=6gT zVh$dB1mfTRicDj0imB)0{&e8(N(AY1{fT*VjXDbll>=sjBPfatQX*7!*Bh@DRUB2A z1*oN+$u3^|t2`?@9K~EmhAL1=2>|Qu62`f>zV7hbnHuoAh(--8*K~qipV5ru0k^*` zAg1+lu+l;vy&EpJfDlB5VJOnxiv?S;-Fm&6@*2*B>l3j$bN_s^#rAXUv_}WJwr^@* zBvf{B0ryq~>VnVTho5n?`o20Jwyv-n=CJ%#WI%Myqor zMn&NS^Vey`IqhG%=Ic}(0?1pvjj@)fvK_^?L}Y!elo0=%Dvkl`wZJXIkZ&jegy*iZ zN;kK>9ELx|A3!B^d*;+^K2LVbdgkD+j{5PL%@z=%l(TTTosXdht3PL}6oL-RVpe)) zmY0DQj*X8@@}hc%t9$|s>GGD(h|Ave-miN30eAoM=A~*@Gm923GNJ0!H2-R}Q$_6F zEnaem8&~Pk+G_(#3lE01(_CqEXpxTow*W3S)UwKW{v($v@oAVRe@(`2|PLkmYEtTgND4z9~BF_iATZQbCV zc|nO@CW+rPQ#y{Ws;YJZNjuqD&hbtYc0WlNjV*^x<~|#s)-geJvC-XdY(BBGD>;{D zYE^`+HY4q8+74u<8xu}>W`BJ*)qzq~1sm%f7G77k)weS_VYJYzU$sjgxU-~t=f&^_ zeLEc-mN?u0HBU9R4O=;BH5MPzGZmXbsdog_Xu8GfZaAW)ve(~w#2B31R{2Ymn@-O> zVd@0hRMCH5$7IH2G5218M^8-8WnN||W!eSOruAlhtKs4njmHQBq3~ikZ;Ol~K+&}O zVqTX$_hioog<=KAgGM?|L(^@V0k8W(q)%b%Xh{e2w@|sO_96ie&a?cweR8%b*)&vh zzGU11M(6&Z_JLg_vKPvETPj zi)-HVr~=jE(mjR%sQQNo$uWQX#WM_FvJ`_Wd4aNtFq2y3rlc*<1YJttO1&&TKzc5p z-4Zb}Q%tOsUJwcsh)vlljwV2#&23hhHbB74Hr>Z_RlgRMM4%w|YF|-}8lYgzz@61Lw5Sdj1nh zftn2k z8ai9*jnxQAtiu}!XI;wEdg*9jG^Fs+G@*UY@ON-Mk@`8FH1AT*XBP5HcLdFRH}@zf zYuvZ_YzO{9gP2D(z%*N1@A3kA>&|-=a^S&4`-hF!SsG``;JH%?Hji*K&+7U zTxz}T5@Uh6_hvc#85+b#8|*B?XgL^A#LH$GwQnX2CwjT{F|p)xir^m!?A` z`~C7@etqc9f&~{=$Y>8wBA+VC3NDQeD#2x_RKqB^Gga$r1raX*euIkDkZ@*WZjv83 z%9K~VX5bMdunp&FJ{x)A{~PE3z#|`6}JFrBq{4c zm1*;#t>`blpb8N0#kU>O9vGbTT^23V+c!x|DbmBE4fup~E(5CmxKhUDw8yDzj&v zJ;Qm4`V$2r(Pa7KQ6C()a?r}GueG`7gT0qeL2U1*x2Yxi75?93RaV#X*?kSg$cdBd zI7kXitg;K%10MrnW6qv0(~j~!$*mr2GfX?KX9o@mCsc?5`y#&Lqoy*ZRTlAWi~#rO z--A+Af*_nrV~+AiT2<$?N9|(}cxhqk1!k4!$xu|=+;w>x8^3qjWQPjF@eqMCGL38&TBYU%+|c&AsN`U)d(7VkVjQ)sY2#ihlcR-d{Fgcr3vUUEcD(^Q%F zS9y3U>AMGQ@TA}==&Q0FuG05TU}qsZ|M@wiAYU-5zomaKt{nW+?OCx-j7g@1EWZ&1ZKayt+IwIE*en#>X`yvpYo89FohUp_N7ts=lJk#{jYKDp;CsxM+;$|x)4t(bfCxwI4<#} z>wg~m(#)qCE069Sk208DT*0WF0Tziff z?J!J0t)Y^-y3TO~N@IV?n#gq%!v6C?FruTZl~M1HsRFW&QM`C9GUQ`_n)9g6t|!X0 zrkHJ5VTHA?9TBH*h1HjNxL-4t+&#V-)NoZqU#N{8$Nc5SKY3mg(O*>Rp)Mv+%${c1 z|Mmj3#PIbk5riTebZ|Q~1xs$%+z_)Y!=9nxZ70_WlKzDXTMa{8;Er|$fv=bbUMyue zz@!oyf>oiP7Zjs=>}@QvCr+Qnv-7ppdhjmn+N0CelRzr~SNEdhDdpJ)-M)KYH-*f6 zA`Qv#_0}JhnuW1HGRCT~Sqz$R)imSITXss-1o#;{($&b48ctBn`d8;aKniH}RB7|~ z=SS;I9>4dSaUeJqH4X8AZ_2Y+9bxt!pV1t_un`b`5eJ9h=jp(4&&S986s=@pe3QMG z7mVNQh909l;}pSb;8L)SzdDge{Fnxtn7yI^&8J=Ny+muPjiR&8xB#PsnrPPM_Q%Ic z9Qf_j^Vg4@8Nh#KK{u7K2#qeXCjPin|REsMrmK zfwqKEe%pMlUiU7eV>f9Cw!N~ey3)Fu8~3PE*oe!l`Q5KNNrKazuKjd0QNMfcQc)b3 zPdz7_3}iZY06Jv%e!>MyKZeA~ErRxlViSAM!rOpGQj_imH!h1iM6C~4mt;U7#*%X> z7b1sFrlZvX47|h_%I^sHXx@*w}cwz_iFa6FNoesG*;$jQcnjg zXBI@&nyR9%*{?e@L*;G_@0hRc3o$xb1Iyi8U08$C6TlGlakjxMXdQ|Nj5CcaIuFz? zl4<6fXx@zPU0XgYwCJQ#8r3>#c*d4JHVRJ0wJER8j#n6i+U_p6PF{21k&$`+0#B$7 zLY4=Sn|I{wSOiR0lEHfq+X-qWGXnaer!(ot0_SEo9jXj%9a!V4eA)HDmi zYY&-m2Ye=**2A7$pAVbV>AR4S~@8|r=$F$>Z1}5c!Cy(JW zl0#qK4^a6VMB5d?Q)h^wd4n~EudU}9k9_nryP4t7>;6YhhLk(RL#n+QT7-Yph=l3U zk`O~F%mCo;tGk5f#q$vc5k&KQVuoToG(tHg`N**J6;ubX?iq4i6f11STI6eRJK$*x{YJ36#)eEpMrXt-429z;Gr4^xI%`r7vfy5n?ZHiQj?f{aY( z_}M?ep{?HxJ6%3g-OX93I7)n0mXg|nIx?>DOTU4?eTMdObv{S&Y-%}5svKN51Wmf( z>VBjXUZEO646VcH>N!AD zf{7Qd8*{G6bNeJUoD(2UOU^{F;K-#VA8IQid1EuGPXa|SW=r+YmE>Ec%@v^OZ+fRP zt1khX+jo_r8!$)mDN@Upw2_tADYZh9{GYRBB>Nc4YV;D_#)9KfvwskIWvlK zZYK`2-ZV&taDp@F*CI6`9MW51ev=nkjlGI0uEXC|(P9U}vquBLt}@Vb;)R04a;Jra68vei3PG1HgTXOPw@}T*e5`u1zB=ZL;1Xg zh%PtFUL-mnm1I($K5&sg^3SY(x+L@GPo*Vq9!DuMcIJtdA~eW16&*}NnMH&7T}2ua zP6UK{s~^P{!~#sD^1!KA$iXVAcePyuKlF(bNwTq&nkHHM(s9O21isdiRPfF>U@F-| zU`8B*>Ss0=d1!kDolmh)tA|alku=L_DnsFcJa2=R0t}}mC73H*gJLqG8nzx1;Yi__ z8z`DM6`md{nJHT;Z{37xoRlpm&qthvW7aNIeAu90c&(-r0Zb$YtzYcUwHRq!j=~UA zpK{EAs(?m02&;kpi+I+PqsX#hq#Gln4EytQ=D7Wkzq}mQR z0W^ee@PBa|`cM6TIAZ1mxH*1CH7Ng`&S3m-+v<)q$pmWeE&b)yyyd^x>4=E2x$5ScnQ-hn^P#0Gq?Vj&(S1W!+)Q)0<&*t^^;?lKubmzWm-E=r}n zs_PN(8>*o+9gS z!gGvXc+{|61fhfD=E?K>@NT#%)*H)|7o=Ube*W7kh6Atq6hT4TskjYNhgu9Azj}Tn z;~T*6wtTfqE$VgaUOeE$A!jJqST>aZH4OT^hwOsypR#N2vG1E_W}n)b6hGKr)wk$m6Lm!> z?%Sq~f8Qh!odfUmEDq8TFcOt8r~<$fnxEWCzB|r3UohC=?jU z4Vp;`@a%J1xW#jNdM3cTL30B8ncjhNNY;1Z@BEW$*Uq!4-YrqK>$zqY=Z^{GB7k@V z7|W)=Oh5^V;OzWb1K+(#eFTDFFplNJU!?Sk&sTZBA!G4c_wv8N%_tw{+0kbi$f0v; zSjNSxENs{X*meu#U>s3h73A6}1ueO8TS;&3pFHd*ues=(dD^D6H24HC6$4ej@cA9< zv5KCVe(TsB)7yOmva_>&J6}%k!+K)R?oM~&zSw8IV9j4;B$^BzQRDuNg=dB+qM=hB zIOwbt2d68$*-Rch%q&41P|>3SD+37cNvII$K$yVNL)4+;K1~<#Ep|(+8KLB+JHCJA zq=v;SlYE@t=KUeEPbxyrYr;WnPBtVYQ9=?2dwn5}ThjW+*1yoEh_{gDi1ShbEHF&Y zv+QUz8PTD8)t$QF`1`_o@8sXUIG#yX>2c$Q=B_knYf4bKMtEVPf)Y`q6#_tRLW?l8 z_RzbqGdW&Hl1#%R8kI?I#+J5}Hjl5*Sb;co2w~D18AK zIz2Dkht|!;Ls|%Se?4mYiF?x610w^QzGk0onn>+CRX8r=;kkf;U1g}6$z1CiN2AJ` zAu0x`ztM>@9HN&HO{gjhKh?eM>xheVDw7zT0PX#w2mAa^sc%Ur*9 zjXV9e2@hXzq@|{s>_stI13c$mw~)u!?bJ3el4P~CizF*Rxhb2W01y59pih7KLs9Q!RLqXAs*8Xe-F|WD@vF`PBWVcb`9>`4NP!L zTLrmQy0D-gQ(vz$(~QXs9^h0DZgR{%>V}1#_V_)!HkTVQA&n`gsC$LlOlYA(QZmrb z@xi&bp~xU92tj^VF5CKUNZc{U`gQ!Ns7dqnyC$PtPb#KeOTETb$&wpY1hfpd|M3F@79SByU_1NM2Z$;Tpa$BQDG0Dck{VuYcm^^xMaVyAfh=%=HOL#4ab96? z=aCGR75kx zENBHGpPzEW7d4Zq8Y+x8`aoD@V8Rs%$RQ7mVzmdzfeljntg+Io4gI`lfJ{+~sJ%> zESV@VUaz>kJ$d*)K)kF>P1qFnl*P`9l_$srr1pSsSB+D@fw*ftpy_ z5)?C*vcQG(yhpm3qT|g;M@$}O{FXJT%l#GgZCMBk|KSliy$Xt7m|B4_WPyV-yoF5& z^MQPP;QPIvzP-KOAJ^)we7ALfo!0t&u9=oyXJEA1b$>ENGKuw@Ui6xnb^smNiFLhz zyuW^=ozEC79P6}(V-DH0US!&D8R-B^9q`}efEN;7W{yhq_rYDfWXaE6>otaP%ygs^ zNUYdz#zob<4nN8Z?ix#NV&>5-1O`m62K6*U$@xSt(r?#w5OO_B6WT)c=njx59WB4a zi=r_=t{AB;kWG%d!7-d&rmf&eLet8^B_F(1RCV(5t-%m1oJe6lG1KO0!G((7oUw{m z0UoK6&R@jpbp+J0>u;~)j?g!E1f=VEm5L*6Ss~pM3$&K~l;4gmRgI*{x}zT|%$ya* zAke&lcC6TnSP0Uwq9=}@WS~s!*wV=jcF=J8u~B_=YWq8Bk18cHvd9}Qs0&xVjfT3` zLX-tSk$$Tf*p!flTfit4XS|tLF^Q?v+Rro03>5wD_eQ$F=FM&ONney*MHP%kemG7T zybZgxz|7Iv#KgxZbU;Za#a1k+Pc^^Lx1}%X#@vBc`K11xJ1B^VV$*XKAMDdg5jYZ5 zdfSPeh|p}u(-9~Ym35%R;OR!UW=MjK+`HKhU_Joi6_VcBwDi|AMLoV^8RT(}P^71D z?61=elgjj7YmV|jvZKxSVbpW>*paUd8Tfva=QT+@5^==B&+;*Kc5PA8KX}d8#Tm)FhXX8P6k^)P-l@UiUYBEh)P`c(5xw?}9KBB`!Ke5<7C49;WVK#abAZ6XX(ZbLR?su!{OvVds+9WNKMDvbD5o@ndM^q!LNJQZo-ikdOVz<4xF zBB>FG*qYma6db!T3*e3Mi*KS7PkvG;p2R@WIiv)+Zp6lqo~%OV;7c|q*xxLtvTDY& z46hC&STv19NkHkJ=CjAz?i9jyd#ExJyOm;MinLyjrXUrer{nYSc)a~|3!0diaI^Du zd$jPeQPiN7uJ^%-tXe$(XUCe|V@7Q4uG}d1^@3xwxkdOnRz1=e)nUpT>^6{${$al8KwSop-FU=rBxeNyg4YBGUuC+& zU#vtkjZ>IMdY-Kjqh!uS|b(pwV}oe$!3och>r zHy$q=KH>$9A}f0{c9Y>D@jMdWUWLQHR!ABR6!7SyEI88Zb0wmNeWevfV!9k4MA%atF|Od0;_+w(*nuhghx>LhzZ)vOp=t~gS%A5OE> z1t39vu6?3t=GiE*EvlpK8iJD|G(d6XejTGwIvZR}1>~tlQGQG9V`H;rPcjkuldDJ| zi_wDCUEBl6)g^L1i+(dF8J!hte#V+e)`b^p{oX8-yzRR<4-C0|3XnFHJ2 z2jaZ+=y8_wL=zIgcB~p9P=d`4T|t39KY?UsCrRDIOPoR;gI-j@NjfU}dnEG9cO5i! zcDrhsBOeX@PKmIvWPfpQd+9-~g*rgV9~CADeb{5Rf*4y&PR-s?&vWi0+w3F^ZUHD> zcQ27aAg>HqyiOfT^5+Dt=LVA$(eATC1_BJVpW?kM#IQhsW(4MB1m~0eQyDPrv@^RU zGs()?U%7#Sab|)_c0F#^38lwn2R>mQKAG&I++njFmE?|Zz5lV=c)t@3^Tu6f*Bmn) zX;2bi-t*Bs8cJa0{&5y$(vId+Zy=XRWt>q#7lH)c1p_V0P4g7o)z!A__nvMQTik@MC#y;}DC=&Dkrbr%U z=%07t;J5!vky!ts$T?{vNwkq${1h+v(ldDkFcrD}L$Xj3GBUBD*czrb>zTn8bkmf} zHD7a#PzQ*kKL$@0-=AB`i?M^48`w#GGe&oJypCrjHLE-yH_ZOvy4BB6>A6JQLzN3u zAp=bT7X!wguT~(nV;rLMcj(6Gsvi$3k9o?51=lVNPPz^CX|)yKy=aHp!Jy)qUN4-4m~c6c6a;ZT>GJz5O`UmC})bG^*Xu_N-*EgQ zPs8kTSp^$)Bv}A!$~HT>U`%wK5Ny{g5v{&=d9``^9XcKk-~tb)8$^D}5kX0o!BZXE zfhKcfVU@L-h09fV@XXmQZ|#2n)&L6Jveuh%mR->31{v9XI2LbO0U5c)9|1C&tJy4{-s`r`Ju1^~a6aRB=_`oKPp!0lRjTTF&f2KJkLeQ)0PVrvH5B8H{v2d$xD7~yNt0I-J964 z%Pa#5-}(f`h@U#8QONphhj@nP^>#P!IHtk3Ua&;MX3S0E)kpK-+Mf>-hp3j^KySYy zz*V8t(|50K4>(=~+yg!KwIW|3x~e=OAiSzrRb1|vRTFj!pFaCb zxRD>9e*w^_nMF`C45~fhxQvAB`mI@2j@5^rZfK9e-uj1LK?P7cF^nKZjI}|Do^0gv z5<}&4jabF8f`)_@Py*AA!f_f`5fwAPKXa0zz*QT&%+lU~$j=^0CjvGcL9H@y6Bq$& z=PK`W6^TPktuypVeDrF0`HhZ5fsEi9i#w`UBhOm zXRYU_kCdvjG(&qs_050PucAHd;qO*-XF5auQ<`q>RtL_F4&ChoBhodh=>2-3lW*oR z!rQ%1acHvjFqQJA%hKROxHFlSwXBW$fTV8VqEYi8yWGX;^>pE8>bC)8eq%>_B4zL})U{ z&+IvDQC-g5;&_b?)Q5ob&6_Xa#JBdp<%Qii5NmG5zy?)nBp5*IRq&(k*f(5JHVOxp9_a#pi6)bj|D6z1x+6q}0)$>`A`dmHE3@U$1h|T@fbi^ypY1 zfph=KV<&uAY5Un}UJlGlIk)48IBQ+q7gL34R3*gRnUqk4Z^X&9F zafUOP@h(%~xaQ?;TR(1ycg^q29%~@gx*H9L#TF8aMe1uY6xb&52N9OGNh0tE zA@Sp#0uIwJA$)YM#Lo4Gc@|=FhWEHSG|^$oORI>B<5#df_;+fgdh_uQkNY0V-O%0W z9Ad4ZqLFOk_mbFiy&sTIXNLKs|CUFK)PggPambJDO`J@}Jf$|Hdma@B;Sc{#<-Irh zIx=eiHMJT9GR}xb)yodnQ^-t!z0T_3N?s#=NU!0enhiZa!jWlVC_=FNq!HWg(iz_S z!8-Dzi^`JD(}%Mz{J2l7Ksps0)O8(t{~^&y36BmtzSmzu@7N&9m{Q@!SI0m6CipV^ z1SgBbV612Z3U!$ai*y3>((u}LE>XO75P&Dp{1w{Z>y2UIZ_9CmTS4@Eu$mKe0#{W` zq&KK{h805$SD6YGKlY7Ks3>bkB-G!%qs z*@f4Jf^kYW&JS6`F)y!ss@@vjrWm~@B&Q@mhx;(scElGp9bK!$lX(R^n z{a*GDf^gb|Lg-!F!6ZA-wq4tsNF<49nJoWW58tcledpsx5sCvBvLF1an8(hh!2hwp zvEjbxdfu(kfvZoXTE~-&nroPu)pmbLdI(4J6b^}bJ4+hmsN;8VNzikjIKBM)1s@ch z*}}(-JJZaQ+=i34wBYxp6(nWz;pV)1Isvadmlyc;g(RavN9skC_4aDPnQapTK73`Q z>h^sT?01tF*Ls3)hO)=ZEDCi>UYAuE8#ypRWGpTpegsc)?CkD z%pDobvVmrY`jKPD4T&C`2JXXc7OPL%p-dQ_k#|2s>cG4ORvzKnsV3nIHuICaSa#-o z_h{SIEZ@kthSC=l%>)NN${h7shga@WW80a{qDIFB##lB*n;bKuZ4Pxx~+Fb>6_19F@|g(*)Q}i2%G*dOy(vzzfPtBYDV}B<3Y@b0`rV1 zQ$c|t$Xm?@QusjqXL>Yb*wG)hrIs&m(NEQCb zFu4#&tc$@4!qWrQq=1U0-15^YWP5s{(WUH zKypllBJ3^0%A=IH5GC`f``1ChghDMFwo28+{37ATK5V!oXbvxzPWX^gmv10(2nQu2 zMD#?XcpUb&Pa}1kKrcr0gg9SqdVm{&@2`i~?oqY49-sG}MUPjyXI%_GtgL#2F7X{M z$YV5a_?nawbfM3Nk4y&Kn;Ck7VmWer7lCE*VV+QBqSV4#CYa6ZX!W2T=l{VmW)35_>j=Z znfpt6AoCpU9no-N!&|DQgA@%kMWYe)R@m3o#N*|JdiO?uum#FwjH5%;hnrSv5xuqj z>))*vNG{twc+^5FL8qe6NBDufI1cC|-1s{&~~KJ5DIbn(#uiq!L)i z=t^zm@sIw&$4(CMiP!~q2)KC zu9WETvQl(@_hTNUu`d(k>c}E590tn9gvaJ!((h`{c9QwaG13qZ#l1_SAiX8w*^nt4 zI*f>;*25fS12}85E%>xol2G2bM+Dxa<~(a>eMXA5c9WH~@T(bA zBg;;!LJSTRmqT6C*9s&tfNx$ImW#cgCcsx5q}`ZA_aGwHN>Zf$_gQjPt|8X?=1=;>g4N ztTl=*X>YTNKQ}}d8tbjCgQghzLt%xYT{RLVi$FfIYlbFF7bQX^7?>1 zLT{qG_T3Ke-Ya^T9_u`OKSA|jYE$sDbZ-qRq3vBmSHybsq0ybLqkwmOeRb^S6o|Gs z`=b}i>vVglzFjHFN^J3&`HIc^Yiq~9C18tQl?p535*K!KlfHA~LYp{8zxdJicfVgf zKeWPf;YQiTV_vDSf2Y+B_wd$R1Agz|n|<3Q%RGqt?SA*$;kV|pwqH&wj{=Od4#b}L z>x>b*z2c^vT;XtadCB{HPlqr8MN_uK5L82$H};Do!|k@7M+}{RKb)XE-^Fz~&V!WZ zX1+SWj*mIa^$$L>cR?C)bw57-5nCg`OVQUige4uhsrYb7fdjsq8^-`z8qfIS$UNzy zcEs9g*KS_wVpgqA)OKJ_@7j6yN5I;;TiM%WZ3>QqXSbn+=2AoMc7BUj z%~)O3=Qr_e&DTWC!)%4;Fmq^*S#>m&U=5_l%5MDH1dl ziFvz%fu(zk7iQnOec&(>zu{f$ZKt8x1_jp$r;%qHe+4%sJu*rd*8yTLZ#v^19W@(( zejwUj!SOLKt@pq#<+~k=CpdqoPaoUr-&V5IvFK2`2Jn(7aHSmiZm{5C&o3N2BXyt4azRBzSV}lT|jp7MQIrjUJ6TE*7Zf8cDATzXuL7b46Kdrg&m0^E!}+*ay1JW zTu$K>(=HqluyHDU-1d zVn-Q*6E@s3P1lzJxWHg9!~3sUAu~P zJGR|5Ww^$7cFiwqnj{WqAE1_9V}HP7)h@b{|E<1q=sZ|QOo5<|Ef&HHT`OSB&lU~5 zf5iLyRPdgj%K{la`c=8L;g`dO%HY>7zFFB`d5vXY0|+BYa4-Uhs0&NJ)+^1JtxDe1 z=c9*sZ1}E>d_MP_DZ5V$cnBEO4jo{5@(oMo%nP`-Ga&v}<=Qe~p>ECB)+2;r3#6fn z8x%N}p|n5RL{C%BcR^RQQf{_g8;1PyfqzfU-9a4@x;qqD6$F3AA`qR6q+*?*o2baw z7-4#|<&P|KBzmuvRn2$VbBIdL02M}N6Tix(C~5$=Oh>hbKK%&q(#`fehMYi)qeSq`|#Eie={mtY$ z)%)ck@8I$6rly%pz1&X7l30O4eZrFv+I69n#y@QbN8Q;082Lw#)q$ZLujGcdsS1KP zh7jUsCD1@ZL&76Ed7gr=SVMT6<|Of5+jTXDOHz{{U5K=AK$k!RpsW@H50H9>rcwg7 z?fhvHdNT?~$o=e7QJo~=j2H})e9CfiYIvYw{5|nH3K?O4@0gDeG={_dR(<{h^9LfE zJ|sbhM^aVu%ZB=$jh<}H}sl4G5b}Yo@ipyNk z<(_`#8sIpp^3c_Rqd8H7I1nPb(FXuP-XA>pmxBRvbZh(&)sJ@T5KYVGl`2_us8rq*!L5P$w;5yurF@*lpUw>lrF8{?te37z7F)kx*~61G^*T*xzTZgQown6p(UXFNNqNaWBQ>KSG-;7b@#!7g@$bRCgV?WPpm=JL7z?)^dfdVAPi)EPNn zz8WDS67YSyN#6OeM2u9TN~k#%GfC3#L4|k``6k48V(Fl%CLzD)*#jEUdAa8@afq%yc>8A()`YGri~cni-83%o;!XlIPP zb;0!8(&iBI*9Ha7eN0yC>|Cam;^FVQ=UweB+oX+iL&HIgbkcg6_iiN>1-v~BCdRb1tu?lc|VW;4p zT*H9B&~-85TH2|mReJZoY=W-{Ic#0DCMj=ERg6wD;NwU`kC*hsYoo~JiBUmGNosW5 zR46-`NJowlo!ISQBb-4@q=P6P2|ln z^}k-NK75liLR64-6|RM;=C|8_LXikF5BBtHgH2SSo!D5!e5hz3{&j_aHqhm1bnDM` zIs&oLixI^pVJ`jkX?AAyAxb$!j*g0VOGp)i>f=D{TO;@OGR<)?K&m~PuP$%1)~t3` z)<6}N0R^rU$#;6)N+SLnhi9sr-NiJsaG2`h#d0a2)3}e3678&tYd=Tmjv3evQwv_C z+X3u0t9&LQGPki(9_V}6^fvhzke88X5=l^T*p*T>$SaDiQdr=!yhBA(nXL2qxL9pCCYUB5>-2swo9ul&QFxy)F)PGr z6E(QeasU2F;iVl*@M2&S)O7!6j>@Cl%woEL;m(h!IKS>qgf4B`?`wB$AfI>htCNj0 z2bH_@#8Nm~;_5Hj!{AD&8{Fq1tsVO9t zaQiN44EEqHOiSXJhTuxUfosNS^DJRXep@Wf=E%CxduSzGI1AfdU57XuE!*_bAxVA+ z*mVq%s}W**g1RUt{2i`H6VsL@>trm8`sl-^l4s>V!51&!S~*K6cp?L>liA?E4*=u;-xar7mx439nf8 zJv_3%ha~!mv-F!9W!FI#58^2WbzJX*d2pLT5bG!Z2+E8m6Mlph>|fqb2S=Rs14El1AZ2Zj;cyDV+o)N(CL>nKW{N3NdIAT0vad& zja1#8umCHF3?w$h3SgnYdzk*X^oTQ=wSp+Kxk5F=BdK4(2m=H>_LNv(t{#Eq1NC<@ zEC6DUQzUm;uB<*fq`f>rRYP^<$_5MNfEC0(;X^u!lZZ2pUX9>W4)9)5E@2%lLwRO( z>q^s?s9KIZfWr$~vDdsY|F|--JZN+tz#yG?Xi~hX%9g#!t-ES(LVV)tVX|!0U0qmvL z@fMo5;xG~0tyrmJi#7{oft6LPraBoruwilnnr{m0#$Se@bcX?2uzLGpiNnmuBrBcy znte#G**_OROyR<;`5-Wra=|27Hxvs?Y4$6G#%|#lfr(oSYg6 z(sDay9+;xL*zVb+XQxdZoNA;)c+(ddLHNwAP+8RLU&{Q1^JoeuD9M+g^~*f}&UA_+ z*cUvj^M6KR7d+;+yLPwy5hs1CtJ^93FPQmfvfkWvHYI(0oD!?r-nyPP)Uo+kB0@bp zJEV8+umN&ZH;`_9Kd-5zr>ZJ>A1=8iG>fl&K){&|n;T@sSn z3#-Q?l=-KJhx&T3%@?UPCy9jHCjk)N>?`*p5#(B?(gw8nV`Ts5SFz!7CwlnE3Wq;q zaMbh5j}Zu8rS>tmhX7tGK3?Mjf;?t51dXv#DTPbEYKgDrUPE6iE1;5Q^u+v;3p6ro{e74_Z+{)?uXi{Aa?fEidDVBJ#VG4EBn(AZW;1t8Q)I zhgf{f+O$7798-e#AZ8(_Y_;~Kd0e>Ui&$G|C_-=wK2y?}a{Rm!^JVAbM%ao?rcLy*_a1id z!8%Ca!7Km;moT3~y2{M+lLbHJT~MBgP@pq=>SqzD7>1I|;nCTfY?8CSh!tc6{oqq@ zeVbwUACEJ{<4Dv7i_r2+b!gT~?a^n!tKWDy3|BE-_swjdgLMcXFX+y<9)O%mQN@N1 ziq08qQKsnrm&WiZd;|lHGvmvf7Dh%ouv&lzAC}l))$H9yAuJmA$dFf$tzPUP8FbpM z&2K~@p#$@}XWFC5`$&hI`m1=+V=@x8ei|uJWZUR2Off?(W_R{`)4$hGOs|JT&nJ_o zI5L$z5K?Sa2z6}y@%fn=wN@F%>VWJ*-fIILa-TSZdA_b0>^o$&Ow1!qmUt3u;|6Gb z5Np+w%kI6^#PJPPD`%fEJ_aCQG2!?SBA1(ba6ePZ>=H~o*Z}vwtqqDCzzRKbO4!b- zXagc_9XCCxCq6fm!#{+HJL z#;s2$`A)P`_zckFrW-N=Pf$OinY>J39MKk-PfU>*Igxbx8xp&dq48H|B?jwGERw=M z+qJpJ>)#3kJ_Y;TU?FDI-TQr2!)K<4P4ZK~E}At}jW^bQRbdCeQDs7fecZCAQtpw? zqh8&!@kIjp#?$a$FNxP+zm_A1xG8e9>(%isrSq*t;0FU!?bL|&8Pf|%Vh+N{`8bi9 z=(Oh0qKCSpf)`w)&i%iMZHA@f>H4DQmc-Af7JGvmPeeBlFeni$(qAs!r60mI@FHKF zf7-b3_%wa`ga*ST`|OY!TsIm9j3}nN)$IQrn{&s*4jfVOuA5^}c1`p{O!aX-RmuEO zq>C_KLGP-H_W0K)?ys1^vRDf}VIY!Mld+tLS_pBQz4|yI|Mac4W&QR!?ihiRvh+hV zm|7dF7vl9gX*LtlXhWlnqe2lTP|!hKpe((Hh#Ua!DT-y#Bc`vn_@NRhEqeDBIg%_S zc+HY|?;(wC?e3@3`N!;rqJXQDN}EU{(fhV6~6NV!;AuBzJF#uGCI1H3-=diAp{+U~%q;PCG%pGqH9onKjR zmuhSzTMvig0j216+mr(V@6@M^Lf@8Qnilu3kRKd!^ZQQulV16|#kI>>) zZzQ_?26=l-_2?U}{P9kb;K^}JKUXMf^C9gGz&RfAz!`r3%<4n(_e6q9gu;QyLTK?! zsg|;cwwQWhlIt)__lir)jUMhY6S4_oD4+h|3Sf$>ukfyY640zI2BhHWlvCfjh2YW$ znLzn&lAIvG`&9uYpiU+9Gvk*e!DwQT@_b|yQ_wNVRH8oNZNBgB!k0iSm#=HMLdsZv znd3!?hy-kC&dl4fz%<=Gvx4ZnjsPxZTu;wyfJpBuBB%?k8oiJGmc?z%ynlUoJ?Frm z*bRrjpHNgjPnUr534kQ8)8^0iT|fDOAjLX7D%uZ9t~2rb;t15ESeW8DTx+{o(D1%4{DHC?TnfN} ze-LGe_iGKOMb|XdxwHU@UO_6v#95UFJ>6^8dXPOhVDN*jV zF1$wDX@Gwi2pK=jzOR#|gT*LQ-lySd8Mp4E`vs5JKf@Dgjkdb}Tm#>};1RjATxdW~ zGyu$k6$BON13AC|w>YE1n3%;?bf)~Z#zQ3%W2DY)M;yX1zL$^nR5hn2H6WM}fA-GV z>wo*ad@6DFLl}X;;z_E0Ghh?zj6`nPf|}W#jwD(`H~|aS8x71clUA}9@06%8{*2m+ zu&ReI2}0*)t)V+GAMvHM)H4_7va1V}QP@_9uH%JH^#a5J*9E0qRvgYP05W!!qF3rq zeoRrm`u2d6&szzxP9tT2tPwH92?*AsW;5qyh~|(6qNp3m?#TNmMA%7Pe!x)ZI9QXm z#YHq=0Y+g1cYOp$LU5wpyy*Pjs5UwXIBa}CFTqVjiT5!w`Z7FueKuwlQ`%~Y zhB5y=S2foP%Xau#`%2Su^SRIp@dKyAPwj!fgsrWeTFT%~FFo){MsX|01`phg7I2Ye zCGB4(ef-0=HeZ;rmLy`_Scx@%#Ib7s)mRDrkS6PprZ!*tUm?DOEu%TwXN>ErC+UcF z;SvdTpFks`Vet(QI8213e@IEd76u$Vl?;anyI3XZQr6<2$1dv2FSJkMivvNlUp}oQ`jd4Jv+5?mUAXnKenWjtxVyT!vU+wMFe3|{JZQ->S zdQqnRFQ<2M#YMXG3AR+_W{PlKDJ5@|9iW1Q^3DY|I~|pXY?K1O2JD=K!NA@AspnUe zVemlmKU5Gbkhna4EkUohhmVil0q^7ZZqJ#IFSrilch*G*oBL1BKS*&7yj-_qv{x`v z?I#Akg~0|(NiMh{2b=N#viSP%@8^4LPU$whfd{K|_S$g4pl8mn)|;*;cJ!|{Rq7R}UBX-)c0av+dCRc`=Y~|KKAuRv$%#h0hFHM^+qKcP z(3qJd0?!w)e~XCv`_*NxKE!60f9O!LnOQ+X2=jHs$5idNF53P&E0jvE>nYtkvqW%JN$NoFcrMZxt z3#wc!y2$7|*SXluH+(Rtf~!ev(?I$w^=H?|267Viwtw8|7&DGI_P?DKnrjs8@81nV zz{dU&K3PRwC_+k+0{iH%&vMD)k2fPTLwl7TV<$E<8n+*`eXzkkkTSeKLPi_jGx9*7 z_o!JkL7-u2HCpc0Po7PZsvY6PK%*Cq&+J3%SF2KWl=kM(V&(mG+1;ib;RaXHoddW+ zz)N^v!&H))A541^d-#UwB&&Kzz-9A~+&>lzcuMeKHw(71*as^z)h zl->AxR0DYUVfXkiyVxy|=c*}+&b6OISg?H+sa!~f@oSxGIc7kVVb9V+kL|%@#hF?z zW>P4BLPYdniZBsG0zaE!>;PqIp?C({7w63KjK2OOZdCzVW02p$^kV8YQGH=ZN;}hL z>``)wWTRlAq)RinASQ;nGHezuQ}}wup&deTvmy1Z0kAB@6Ha1nR({QNOko(KCL1t0 zU^Ik3Nk9-bn~&6~Obli6z_?mj#bOWg`obDaF=~OcPlzbfPgM);ildIt(9!r2#t6-u zqNB(rm=Kzl8%pZ1nNiwJB-jm5=_E|Bij|%byfOM!PQ;20&EDweT=n9tAPMQ}Z<`~a zDB&;LWboI8XJ1eltX#&t3y$B?`TvJE5q;PHF#&shum41}!v9x9tJyuy z{I`~F`)@5x{9jsn-2yYrK;8v$8)<3?YA#iHG_o#vr7ju3>&6li;`SqR>R<6pNiCeH zrI9;BvkTzq%fNS(v`=bXHA>}U17@4=de&1=rr-IVk|S#q5$Idj6pCP4QzY;{-7}@+ z^z;<}%(Y%c^(RaEX@Y_jt4-shOY3>B#QZb{K$g-uF;2&ccPK~*E7hG#PL=7I=F`y5 z#CaeqAc;&(w}0T1{P3QIx?b4vz$t(CY>rp_B^|MHt$xlr8mfG$YofxXNCIY_p8Caw z7W91p*c-XYjppTvdkgsWIo|U}mVDqAOfckb=OqpzIQVz$o8kIu&BvcSn5oI+Tq5GH zr(Z8`N3$@1u6{TP-`X$RL}HdYS)q#0gV#s%OpN#W#g2v%F>EO)?vpy@O0Os zu}jm&{yKIzyz3N#VyPgh#%LW!L-@U}8)NUd2x7V~T+8kA)#kkFfzrXMvxRiBT=Trk zESGQY^jGF{EppHRLB$&)&Emf1HbptklY6b7z@e}#$GZn}<=cre8oHxk#%kSyB(B;m zNY#YD0s3suaAf{xHxPn|H56rE!HKq>csjVsExo_%r4jEoi41(5*{l{ zkT{Ame;crQEkcg{_HK6h0&#z&^MhQLhQ~C$MSTgScA6lmR}>f#z3n_ybtzC;uXRm4 z|B>I^MZyu%mXB`SPgb$UDBXu&IxTl!+{jnEATK_1+Xg!mIeG=uoSBL#P5Kdqjb606 zl$zBj-C?t@a0TJB7ZEqabi*U}t(>?n*X8;CFX#D`ujfZ!9U`+!YM{s^CPC|@y~PHb zq~>&_nWp^%3Hz!s^rGk;$?5Z0xnTZ&UeDWtTb+R~&W@?tj7-D19j+SYN#O#gWDTV^7r?>oKFP4-p5&g#N>gl$5@Qf3HA zjV16&(vrwh&d!3l`{hKx_WAMA)ulDmRcgHWpVn#2mr(Kmq)=vcedd|r7-poFz@>bU z=yF_A7Hx%BAWVh+4LX+@rb)1sDwbI(s(JOAuM0PQOwq#>LYaahtt*&_j@6^Ak=$ST z#oK2y>+`*V5j-~2_qEyvqmp1XFkx@qCT8tQUYa(95)J$6`^m3sB8%~!-2749^TWTQddmhxLJop3=}?Mg;#Ltjg8ym6fTp@uAiboQTc45|4W z+c@4K(7frm9m?QfGB?5%v`;nDvq8Rcw+Bpg8RAz2ITLPW>FtG`$DWwS0x|cMe%${}{U_6+rT1R6!MnJHH-EfMZr> zT?6^-_64b82AoNidc3;E;=T8Um4k-K=M(n4Uorkk1-n8}8gX6ICqZi`;QM?%adq%o z%)&Ar48s2@YQ9qH**1J##eBDrK11Lxy0?gLev-OQEnpTex+OF9c6xz$k_60$KStgl zprf$0xd;BUxj}y#YrVM(T~_k}7gph$bbY42aDNj`uJ%ahVqSVjKNn#?YiU+MJf^v- z=3$M#osqRYG1QZ6#(P|!0=iUx^AFFAm3-%s6Mkvpz530$J#22fFGi46JXYG{mhd!y z7xoObQ?=7?6ny}rMdTLTCS}P1BoMTz-oJA1DaTsyDkWaiL$!n7_!qn{Q{d@~3Zp2X z&v4F({~_Wr{M$NZOcntrmrLJf3wr#jS<*Gw=c=dj^K#H|bye%xp1)5ZsxOW;ePy0n zGm90H7r;)gP3RRNHX9rH7yb#3dDmjUeb!xuGqwb8hjIw@y}{8SCrp?MM+Ix0*{+YP4MM_Y1d_Vk$zw%mu_hzHhbI*D|_JI5MB# z+J62%Q&|cAAuEN5z^Q~@c;$f07e{yydqSsP)B)}U{1G7ky94pFEgJ48%6%yhxj&(IL*8%j&UKO8&s^a9fsyQtjR=O ze5+g^tA4VZn0N1gVcEM{b}afiR^G;fMz(=?*N|PiNuYRDf8aj){#OgaNY0p__PjNxS$*O|HfT-b})$}W#2(!p| z#kqs10i~-8cWJ`~?#}B%gv7(U!~NI!Y4aV5_nfl}xat~15Av}5d0yNa_1Ix`jL`2f z6D}bQk*hc)iAZRWJfcNkv$!4oY)dfiyqwh0E!bF|fxpvUS7OjoMKl)o)&j^SxXC#> z4Zdzc^E4{7$TN!etlabq7oqyRM+$ip_I$u|a<(LSPJsTZ00um+AN~`74;EMm$C1Fe z(>+<7a3nO;VmGoKw~C|(t4JLi^7nhcoR2>~&c6S5l(X{jc5a`~z;J;Ma@86s=6#jA zXMj$~^QMEg67Trg7|-`-cH|a~3Bl@gkVU4bEU{IrP?AC5vz6JIRbk$gs-*F&-z>NE z{LJV6lvK&b9){IpEG;nex{1DE=GDhf^!0Z}<3m2sTqQG!{y87(15o=DlQ#t3sPI)e zuHOnxO^%hb=K}%B5&l z9x1OHj(ku^^dJ_GKj}msC@tWGxvT^zY*CypD%<-Nmp;M7_JW@q&hwX(mb|Kkb;rKs zTIZ~#d*r+!wO8#zO>+jUB{_wvkQEF8z0-bEAJ+9{<`T!NzAUnj3(@k7F5|}q6t2OK zu&Q~NdwH^J1oB`|L@!=h2?;JQFLu9+JSrG4SSI1rAZ!8OY|qcV^nsr+>FGu7zA<^Q zsMt8Qm}!>gB!5LOf+m;D!0A8w0(j-OpHS$Y^B~v986= zqZ8?^6^x{gOR(gD> zX($K^Y46ql9XfLjS?i6u&Q{U+>apQJFpLY6W@O5=?d%GB$?LtAi?&0=y^Kw&! zfbld0fBLF;c4>y6Sd)~El$E)!W<~Y@A_Ec5{YzeQPrB!VIF?+9cKW)e-3aqKeO)`} zmcS@e=HeYzqh*=tW!RJgGMDU#fVKqS7JfbM*P3kullzfImGXPr8!JIv+!SyF8|Q$n zGYEK%d_0f-M~OW^PAz=;aUd-iGvZe*UzL+`9vkWz=We&DUz^-5{0$k9Kyhr#s272R0mM@3cg*2 zMb`I2|C0iuj+1x-OW5D33VPinzWa~Y(@{AOWF#ilEj)*H+Y^1xdiePPePF!E%MpHH zvZ=dfEQ9i$T+7^9D(Vg*r*E8w5)(E^Gd)YlkB59@(Fy(=b%l;>hZ)@hq+p6&?n0;ijQkrHN2^Iv4qOH*W zIo(rXcid7*SQ+S){VtLj$Z)ir^gA#^r@Wm=22fDX%=7@2BvVt1M-50YbXyGPSDVo5 z=t7T>$V?L!++-<-R?0Toq~@cSa-B8pCL)WM>m$4frA27DrSqD`E~|vPeAh$^ISCGx z;4;{5C0c@DG8HYM<^Add1(M z_&yj;wTgOY?&j4;4~NgU*z;tUk)D|Q*0t^X?c~ysUFOmLU?zhfPtq~*h=~Q_;mHvQ}YQ7^O4NaU?E=oaBv zNPN`*ms&o@FZ1nHU^4qK+nhAy(VdL_OIrET9E~(WmP3niRtW$@r~KBOb$U+# zzKX+hp4m>$DF2phGT&CnxU9fY6TC#~{c0mssG<0W2rM^^5ZuQp+bo|;SeWk5I|M_$ zQN%$Oh<^A|PQ`dw#VDFV0%GvA2*wfa+-X}MiD7J2CChg#Uk0blvwhn@-hSM&0mnvo zmUGY4C7dphGy!7aM1S|uBT?qTj1|Y?m|R+%;EI@?9eI@M*hS3k8JiHfMD4w)-CnWM ziU!6i_kJ5&X|~qNU(}>aG!&4?#-5o=5z@t(!5uNW4<&Om(>$WNU}ZFDpw4%X8pQew zlE)Zc@QNk>M0j2%P(~cCiZ8yv3%bPvRnYe|z9s$t%V{S0u6w`N|GGAZkbSWGmijOM zE%izNBlY|Kb8S8>DE&#O_E;t=yeu`-NP#kzW~#*!MX(MHML9b-X@oyIB?6FL`PINZ zS)cv&RePo^aaR>#Qb~dL$xs@L*mK=gqqEp=Qh#6ih55oY++1&fRo>(II)MeUKX!2T z*{VLk;drJz^<&X9$?#>-fW$Gv`Y`9K^89l($+Q>*yXy#e zj)H*x2b*ZoqI+18HE3q14>SS-^-d&er}JK?*=0v^_VoVROOHpS>CD!-YrS$$NU;In zBpuZ7)n~!46WVd_I&?Sp#0A80BzgbsP@lK$-_(_n^+Gr}R}(Cpq<%W+9X4@)lHeL@ zb&a)(T?l%Kb`BBK05*(Pn)};l(X55X!nMmC9h_3S^ceSn_TjS7aCBGkn@{UIHp-M; z`{r1_Ir|{qOz9eLjY>U->C!NsNhc@d4tlL-nCR=wY8L@WnjFW50>}1eflA16z8$`f zniz4MT;XXbBzB=(Up*w)c~ z(Nc@(A0<+)c>Y>|)`ur33RZ@5cpWHPI%l`rYky#psX;Bx^*2P)E$nYpFyper*N@XH zDIyibcqqY_0`c*+Q8sb^73(Jbo`1Km-%&f){u`ayeAhho0G=KA%G+{iWM0~)s9z}RDusZ5Q1%%%tK?)1 zPiNm`Vz4)@)s#Z8R2Jv)M9@J>o;YoeNpq`+U?os;DwJH~jl z=B+;^zb@iBTrEuc3cSE%(0OrkIAu#Z!RW&6n{FS|EB$wN*+ALCsx`r)_1P%gB#e6$ z4d=#_8Fj$*M$@kfUcMaIxe@pLzrrxMC;4eB^(tz6lb%3%N>sr^Xj1N|bQ%&Ev6N$I zO!xER>qswun+yeF0HtTik%Tc;JRA|DmnPR$w}u_z9QxXPbO$OP@RR4=JU!O1htDiv zgbRI65#PJy2pvh%T3cr({ge;g$Ceo$!)jy1A(cV@d@(XkjdjYYzZ3H`sV8nMC!bYj|->Vwd4z@b+Phw5I>ujfLw0i*ns?NAuPD(NX47oTTRoz2R=eo%v9j@18!zQ zJ3aXARbVVt@(TwYd55lKxmtB+L85Dy%OThA+K*Qh@U z2F`nM1+l+zdJEoYJmU(W5ynmU>1ezsZ=z{E#Z%HZzu<5T`!M0>{r&gFwtQ-P4<=JJ z6lw^KM`}%JU8mqC@x22d0zZApxN1m1@rt@IKZmJUV?zB&3<$fSYqz+Ee@YGryS^9C zPJ~Q=+kFh&KO>-P?tg|!i_KM9^)zr!imhu|M>KKNh;-?%FkTrWT{eodR}HbKA783% zl0p67arbqOdM02ZbU1#}0L~U;yP_NYx+6YsxINdm0OL@~s@=@zLF;|Df${C|dd+`C|j zPa*oFZOI7{kC3P&oya>j$y{^178(-DJ@Br%t3X5!io9^@%_8ZC|n!l^a^?W$SB zu>M^TJ~{>tX-F0S%gqU(Ct%{%49`5MVv3?{6*it{RT`)*Hg}~Uu#PM{f4>%GtwjjM zky5}JK2x(BnJ_B>bny!Mhm8d}H|+7u`mV^-ZDvTzSJ`EJs$vtiN?E(!bG6Y+#NVML zLI6q2py-yygSliB=*Mp8SIAMiF{c5KSBSPkmaIV*>3O=l1zK&Qp*$W>{_AbP-gp&7 zNb=BL2$Uy@k3hqhdQ`;Y7@&uOV$q;Q3yx+ zUXc@H6LnGv83#1B#3m2#c63P!L%cBURKu58kY!ojBd&)=Dtiw+r||oyIFDCQv5QweAldCqZZA*mPG!#x)fgGt3Rid$!AR{ zMDQ8>zW@7!39xz#&N;luM_628Vya zB#yN^iP&XW1RBuV3i`Ldn3cx&yaKU??n`6YB8UEp8E=J`BMpbvLjrch$ZlnMbI#Ry3 z??Kz*x2*zhMIk*RSyo#B}z83agN?zX`64PjT{b?nrLk zUbW6Qd%I(^$zA5*DoK5ByMth9VXWHj?l=iXyf*8AAY$y~B;7ZH`nHNf>G28fzl&{> z+A_IHmgkQJ0_xc?{dNIhT*$2}yj!Pqb5=Tt@=pwie+p*{L=`;#1OQJ_TZZ&Obcz^* z#~DAk|Cm?cx6q5+3#~t_%Dm#jqZPx>Z3`k9mp<_BO9crp4H04~^Z2r1!j-%{KM?WoOu#|IP(~%qFq zTC(sNfA1K7%$gXL6=ZJME?9vi1cI9`T$H^ZX$1c_s%?Zc)75_Iv>m&`_z4sF)%HR*{5qxn+`J|_NWK-Q%A z$rHED#C9119YhErLRP$kLE>MKfwXe-M@kZ%E5X(RPGZB`8X{w=4@n~-)y&iNc8h~d zUzGY!4VR2kf$^MGhbOWcCh|H))5_jzDG&^j#iwvuEAUc`yFZNihFn&bNNeHF+fc%r zvKgOB^5S0`nauOD%2#@ZLa^{MyXkMG4_(K~C{eSXhVE<7&7vzHdl#=nr2`QkwnE7@2J zkk&VKu-Rb~P`l{zgSZh9_Vf~o7LUe_ZkLwhSmns%^41}N8z6?VfD|-n8PRhn9%;^H zufHTgwBh3slfwA_gO-_%!OEPRMN!0h>BmNiVo1XSb;X})(q_-4^2vN<4=Uj_@$rQ1 zDNgyG3mxNwio&h{m0pd2L!M(a!OJQrhHpoT@$G>wfPocjV+`brFD$F5&`mo1D_~kM z!swu20mb#x0OC|Z_opX@ctjzKKD`o6FMn{>*{?-unqzVaU)}a%gPkps#CULTaPzUr zeC$?#h^EPU*uFo@Y2O6e2;&WnAeL~kP~w0%5ZGN84Dx$hVzd^2$o11utG?X z!trUA-kKjT$;dI$S<;rlDSm2L%)po#H=y60{{^A^r7_6C=>O;xkbT#E-|K%31w^t8 zqkeY^`v1FAK>nXj!GyJm1ZKE@$`yBxia0&&Sv5SC7OIzIvyGOd-zYXxt~_sE>}Iqb zBOuEN)vG?^2W!HYzYmeyLZsxn7uCtS-u}q5;}vyufAee5rs>PkWp<1ErvHB8>LPrH z1g|SF+-x5#{zF$Vw>y8)YK3~M9lKp>Zjel6+DLo7DX0kfkxB{`q^mmm&2AYM5s>Jj zi)mO@JfH7YwIfD;Gyw`Pg3GNmFr1(B5n1ZxR&$ckOuMi*#M6n;NsR`>vx@_1O znxFWhvxMnZ(yi1qF#CAsu+@=0DBOb#HX2~Muy72ITaxw3*9zi9umg4;3g|2jAc@;7 zfod={JY(-FBjO-jyo_*&Pj_INU8f)HFkc=SU5&pzecY()Zl>X$CW4H#(F1<1t@!m{ zq?eC8+`C>vqU5SCTa#p)l;{I?R#aZalje7q&emBQEDeC;ITuFS6`3w)MJCLf^_~N%4B7yS+ebHWyyG{_d4=Vs z^A9@C0%K&S>Ib67RHkPUG)Cd4H}#EHFn7#=*tjJL$rzRP%=avQ^rHG41K zCf>6H-yaPorit+)@5k#l_B%n#0H8nKF9B0i6G3LVSbi;_b!GQjzCJ5<1lvs==3k!< zpSuH}{sLY8oc}su8wRE|lPY6u8ETqq-NuJIoshM!31gYLZ48q7jAJOGJj0v?HoeIw z>KAzbv~@w`zdfk@ZT{6qjb|d&`O}0d%Ddk0mAJ}c3sfvvun*h%6eUk0=l*p`{HxZc z&t^Q7zA~7-v{AjZhO-~&38ohJ^5X|(JV{X5{Z?RP%H?5TW)@G2N%Ske%mQCG7ER~cH6QoM}w`x$<2zCr-KAWSWfL63#5Aw}3~80=4$`ui&k^&mc9 z+=;j~sKcRoX`g&lj=&}WoFNoT#9qB)PcpipIPS`igBNOn%jMqO_!Yv7#h*C% zZc8OdEpMpQ{_dJ~*I5>M)Vr=#suznbNv;5LG>H|`oYL)@ zc_OI^*0f#{iFB$J?|I#0kR+gCIS4p3u?K(A8&DfO4$2ryp8=U8IQ2~%d@WrB&hDqC zYArMF`Tcc{N3%hP&O{-DoJu@`Fwj^JDCJ+lcWkf`3DVt(K3rPBq@V16eNe9pssj0K z^#=a|hnzED#^keV5bQVSkxi|mBJ>L(7HH7b_Sx)6?)$(Au3*r9?ALQ6GEq$b9jnDX z_fuO88Fhq6fNbgt>{bRdqVC3I>-o#T70H_`1v@eY5aEzp-uGnRsHo zu{B91=ESyb+jb_lZQHhO=gg`4{;IFef6-OFtM=W#*-!WCwf-0gBX_)lseV5k&X&Ap zg#F3a=6m3!g&XR+jtPe|IQJxmS3mj}TI%fSOa@)w`A+YBeUkJ2{P{IpY_>qOSe}wy zLdE@u1(bd~A7puz-if~u6iHa9m?pv8^GNI0%R1b}#FxBV?6GXYQKATeyvID!Tx2N= zbijxV=dA+%j+$6BzjXSWUQO0Jb)sF(NJnU#ve(n9{o|!W4m(g$iH;^+W*QoTFw%FJ zxV2!t9f$fEV=CJ~T!_Q)uW;(a#08{pB?>v*#@^kZxKWa1n>m%qWBhsZ2^AW)GUbo& zDTu#MYUF$b5cjJY4TrK_rY4!7!umY$X`{Y)el;o#9Rt=fc=C5w_2QaR>tTs(ia3a! z<_<;qTc?6O;6kE)oojX;itLwAdW@&KG7mXfK#B?SZ)4)bz8E5BsbIx^f_m3leDd?U z@ZHlveRa9X^+rad!rxHdmhyABC(JEfE;GU(PEA@VY8pK2oY3NuH--tw<$|S5p3hf5 zn+EdXu0kETAjQ|A18WHK?brlSce$GS9#h+NRL}%4McrpJ z?Znt39Xfk8m&(`4Ev=2g%*bmoC?hx^`?!)5o}pF*m4?yz#s&xTciT!Nr`Dmwp+TZ- z(P_*)hOD9{n+hZZ^PFo|lC3B4K;uxaF1J54R4@jt74#vZ;F?Ee#Jeuf`0fDn9_$Te z)b`2Mh3G5kU+J>y9DWi6lvLZ*TrYy6pR~5ad=TmMbthMA+p0)<^#K~q%%LsbjfTYe z7Jhmg2@@z4rzu5tfWTyowd*(^{+r>p~mP$#CBLJwXLq60I89 zUE^p;K+Dq75JF(!Esi+ABf(|&dVUB$7W<;J@6H}iM}B_vU+en3U+(P@g-0;zc7J^x zj+;!W(YDDbR)&@=BT#-1y5Iv0&(b!a^+S0jsx)Mff~n^SMN0WYo<1noE;NdOFv3_+ zN%O!9vWmM%5j1K_swz$8MMv(+va;+UC#`|o!@ctqB2F@z3!`re9g!upwCQXx6BEw& zr}bbSymP>gXc^y{P*6k2eyQqM5x)gY$);_o;ELJPZ5j%+80M1MeJ{d>ec+Kewpd~? zY+#-@@Ndq-?L$gJ1RRWmY7I<^NCi%Z-_gg;Ya~yGa{*x}m}MC#ZY^(tgPi3ozf81j z-Lq+4X$=frp-~(ZFnV2qMG|9~DgrKgsnWOi#^t5hz*=;p$QWQq`ZmDLmB<+DWl79Hpem4&U{V3ECW*9*colbvo)08I4i0EM?ReraQSx zl$sfRO!!S5l6-b%LD86(<)l1xxcNoM5=MsAIPG*Qm{a=R_<*WtKX#_Pd!GJAg8&|l zD|!9u>gn#sW$$@s=d!r?Kc7V}?>A%i(F5}(J;=)C092Th;IbB|_7h#a{s=VtwsX15Y*YtQW;$jJW*q#>> z(A)9`hjCE9DV?;E_U-nX$-~d=dzC&T3&%kQ@>w9oaZX8RlC>7i4-YnbkBI8AQ#xNc z>SfZwy0I<|MXwB9OreQs_S>qoe~&&uo8mC$D^oC`Ne2|Ri%!fLA=*l=ePJ1y+&gT9 zC%d}aa?azCHA=qvMuR?66_S+p>BgbgRFLz(%2;Md&NT%jEdI=QltD!9^nN;ffY!Vb zak!ZjVFB&n_V+t73cdVWi;+yE>;5;(UB)zE+#1KhDEB!@#D(?x;wQSMbO&!1$@?jQ z;EO$s=?g=eb_1eP|F0^i4%6-p^x95}HB89dEE$Ox9`L}j>s@;y;?)DtPGPSEDEt1@ z*pchQPQD6w^j{qyYs=FPKKjm~1~@5_ZULj{2_)X0v?EIF@yc8AUkmDk9sd1y$IfUci3!rCr649&kCPvtT+uFnG{OG&te-17I@+{2y`^Y3ukYy<+&(lsX$-Lt;<`c<3lR zEK2A_A@cx;pOA0Qm(h`-&zLdj;Yog?_mp!#xY!`io-fN}Z(Oh=R|b6pReV9Uk@v*P zoMY!z1#M(ibZ%C;AOj5qH?WzLONno`iiMn%2?8eG19v49g0Nw?E93PRI70DfZAQhT zrY>xlh)H7MUz$H|*E;$qIZaru;Q5XIvb+T9(=cIE6gzG2%taKYsATna^Zp!2@9c?H zhDJuL_r%JJQQY1kx5uBe7@fxZqy9t~uy@?ZBk>y#Okb_l3xqCoN%Jm`JaB|7n1XtY zw737SGyvFY9P3cK6faMv59j8q9|qjz=MCFL&2@^jfRyW|5OAwDv=7vmyhABQQobp% z!q#pxMrMe%$~Zi+l3gVBKoUj^M0Zu=###V1RoF`hk#7%v60(xr)xzoM=?S!k2`81i zI!301VDq*!4E70Q6fj|6Gsk2Lpe>$e;sg;KhPEY&hh;`@C_DWL5zhHFZM2a!lkF`s z&-RX;jm<9v%TelSF-#fRQ(4OXmqR8Bk( z@lXy-lm&G>>56;KL5lDCA*eZ=53Oocp%dT^^sBNc%pbHWV&(d}?Ay`&g@mmD6y!_^ zCupg-K2XO>F@G34#`kX;p}HUppP_i#%Z(Snof|gwUb=NlpxBih9Vj|$;76$eHgXS2 zt@YVPt)Tqxc5J6sFA2J8QHsc0X^7dkP0BNngQzUG&(ME}OX^$0P~%N)>Cqq@yOf#` zr;K?JMsL$Cn|?EwaF3x(j{)v(+`0kNH!!rODJWhmknALhb|JZS&4(6cQyvXR&2TtriGzGghs& zS3|;(o_g5n!N?~0Cs-!>5#O79-ZYw}nA5k|CCw6${EI_v`HwxXWBh*`y!Xclc$>Pc zmDr9?Uclqlm|Zk_nqL0QupPIfo77t}wM-rKmP))#gzZcmI<=gK*W-|-wh#|`adCI+ zG=nAbFSsaF#>O#N6X*zx+9NkCvTRpA!KKA-@PMk3eBk98X_5-c%PXkpTnt7qU?V=J zu14R&=5EmcsG+&=GWdbcZM296JU$7Th2*;MF>sXQvf)=y_-d$UM%)B4g9)bn0vr?| z*qO@nVnF)N<@|d(y?VAc<^8s{Wtj*HcgLaz+~vM|;d^KQ%%+(oJQ_M7_P1A9@~8$# zdCz%!g=9Dgw7l3qSw&pVlC#P!^cn;~OR{gc8-<-uuu7)te0hI9o#Rd>=LMftr%? z6LqO(hG*-VB--8pO(zWaEgJ7eYnCsa#S5%$IJr)S&v4?^4m$cWs9;ejnl3(1**kcd zIb-8~ku%!}Lg4$WxT2vHlQ(_SG)a);L+{=9U+F-75t(#reL8ePXXSj~Roz-kU15sA zZb8Y-&=AvZ72N#n8|DehMI_us#T>trbou@hH@se-;iLO!>jR@=s=IiCy|e8zNJ9cZ zX}JYA7;^((@tdZjS@b*Cx2M-LnW*D5+WA@D!>9Ab)0waRb^m_xRWUg|GOW^R)mNp} z6lY)UYp)aNuPDUK04JAi2z$kIjz&P}+MxtuMwQ z<$U=bzFMk`(_o*@4{AZs##Y(nrN)9^BS4owZS##o>R{8z{7&t+IeoF_FeM5+5|E5^SfR{dM1OhBOmL{ z=;7qibXS-ES~5erR}RnQH1Z*OD|-&o!65~$I$Zj&p;9pCkwQ~jWZD*VF+u`|?llXBjEF6TYDmY1 zl#__iXcvPE8T|1fV3)Xe^~yQ)9I1n?fe3_40FagrV^iK}*(;91G34^s*zdb0kn(yC zjHq&uY$3#@KJ2jv57!zJ486vb00YnN7oG~?_f!==x`pU?h=@!1t9GKl&Oj&$19hJk zAA4AfTCZNyUInJ|J2NQcw-)kG@w~u4jWvh~PaNhmtKsxP-`_rWrAPB{c{F4H`zk|mg}d$27CL_h#(-cwlH4HU*{09E0BwH^w$;}x_Cm> zCO7@T&o`3WAmqH9j7HfxhAHD^<>U~{{<6B=@nc0LM7c=AaC;f*IcW^%lmB?ETuHx;4A3* z5tMOqD_OagiHhj`u;XjQ)fHk^Q0KmN12xU-<$C`odR-{b$@SS00P?q+r^m3oW6SFp-zfvXuWToVYk}705dUK1 ztNf5uB-F2mHzFZ40q3A|a>!)^hpMMoy<+zZKs_Stgtv?q>tN&fccv3o{1tI-lgmb8 z%7?c&jOy>P)Aa4QS*G3X`T~#`QV4()Lk*bhc!AZcSbmlX4Fl%vXSEOahG-r!gu5p^ z>KEcBFWTgE7Mt-u>AynU`Q<^4l^b5;F=%-EY47?z59hSh@UE(Uqhf0F^R-o9jzg)0 zVwT8(n1Ym@9Q$w631jQ}=hSJl&&{w~g{u;@6&~v;w?x7Z&MLz@LjsFVp^%(bE%ygR zwrJwNU1Ux)*`*JmBKg#^e5J;NT?hI{QjLZVEtw0Ja*CGim6pzd`XznrQ zt&+?$>bxLFFB3lFYZWmyd$kWfJ*N4dksoz%_a!I!6(!98$w)*>3l`cmjmg9?70~ms z=L4q^VG(vq~r&ogfS1zKk2~J)Y zdj0<6T3Krzxo_)ZzJIrmY`ZjFqHAfKPDOk7l(|~%9{*Czazai*!2%1cnv#$Kbe&hi z$E>&m5kVWd>>~&f5K-rqLy^u#3^_3|pv_lg;m9rH70w$O-cb!{j% z5pC4RH4@#z^09j0lIRO)6~*eK_S^sNCyBhj9&Z1wQmzHOKORmO|5^GMCO!;-!L-bA z@t`mCSNm@Jd=GPM^Kxy&IS=_|rQ208Sm^Z?)rr#87yl8ud-&Zz&W*%8BqztkqTK}? z{*=G=Q5T4kHk45xK0K2DSnt-Y-u7{SWIRKjcxwqe*sJKP7v8zKxfvWCt*ixIr1UKt z8=@OuDOjay$^O(%5}Vy*h!zs`yjr0AV9_j~VtO3IN@jv53A_(QCL#n&UPg;3xcKKm;I`50!G$|@WM}DHFkE{RtoUh72XYEB98zLB8bHUEyyAyEVsZa~p|?J-T6N>sr1}?j!-ykq+U0n9T7AoF7@uGcdX~u1&vmh%8Pl$jGNfz z#i8$d*>StB0FS$yr~UQ8!^6wV%WMFZ^7xf#oxona|2dzCO$}@fQk$I65QAc5?Ngzl zFnKs;3XOt@$eh_a(M_r8JG(YxOw0Y=!(n}UGcQFu8ZwlVMMy7yg+Uf@n9EIzx)0o- zQ#F%6^k_+L_fV}Dm)eXdjJ?v0r#W<`G?m6n}P)ss!`RuMoSK!e)L z(5E{nZ*`kmNoavV_y~(}T_CY~Rj1p}*%mc!+P;5q((?;HS_-KNDo6wFLXsLhUd75W z8Dec<(EKzaPUPz?i5%+m$B^G2j0-gqFdho8_nX;WxmKsW)Go4vE*{aCXgi9xJq9>0 zADoo*Hu9C+MrI?NWeCw5jnz)eAju+zrn@V1DwAG2Hoglr%`BiooH zY%%CTt_VQ8yF>~03@$We^}>)3ViON~_>3^hEDHq*L;?<9VM6&RY8bs?K3u^+ng^1Y zwrOJn)TL=f94q{BXje4mO_}!vcv}J(jl!~KdaLRgrTvjB1G*?qD-1F2{DjcNQthtk zcD{>m@k6!?T<5BMrUa7 z*K2pW+C%;#he8w=h&18S){qzA(BRUp9BgUIK*BNMfJ)dy!xM2t%g zQIal)&Ge{4Xp_ixvchJLKcJ&28A-FNSOC=RRs9xE4W~B!Kxv8=VT#Fsk&+`;=9$=0 zCj1Wh%bG#T_6#JF^_CsJv-;MpqfPyQU0s6Ee~GBnjxvE0ib%iyzyauTDgL( za|*p_lZU+naA#8JYQZi1^vt+|&@YBy$-m0mjjC@#(ev9=6LCoc89cSHx;Jka9$}Bs zVNbA%UO`t^$?tLbacTM*+04lV$8Jl=;9+OkZ1khjyJPfBXQ1~)9zcw2S*iV5Kv05Vpf?5bk)e0Nyg{)A$p}x# znWcz00>IUu_3{A77GR{lOH4pW;(|3z`!(lrgo5B;qI}Un5^kvj7$>lPb^8+xYxJ<* zpx6oQ*$3o)+5YOEfL7}NfzOhT_<$~pK*c|1 z|9=X9s(*d|zxqE6FEs<`{KxR+|6zFQe+<9+zs7i|J+}rGv}J84A;DKvy~NT&O+_OD zmh|HSOo*#5;tWVBw&$#wz4RFyTYX!#;8))Q&**i_Ls(Q~>JeSYsONc$Ij2`R(td6W z{F`2IbWvhp);!;ikN3NCsPt-|g?W}4c^L~SM9G+lb~|xnKUpo!$+5p(>r8{YX_fAi zaN5GbJD2x;`V1D~qUYLh+`}2*e=oV$s9n}X{Iv;g4v*HPi!xFxU8BG#%`kQ?s0v-H zC&DZtuzL=U5((PxeKWvu&khHD?18V&P~ISYdcuOKbrTU~ceI+bsm~K6{K1Hr{~HC+ zXyU+M32z&rrinZ-)>K^#Un-noKMlY0a-9L^w}KCI2xHP;HQBQM=XYnIC!5w+0`m4( zxtz}hP85LJ*f*ef#bQT7b8{*uk5i}2|M={|B|5cC+B(>Z^l<+6+3tkp9%7QqtWB*feBGRG{*`Ms${)?k?d|18N&v?jVyp?k zyU#2Xr!DlJ=K7}daXH@3*?#EG2L9ZP(X22Ep%MW;z5oZ4LMr6sm6Xe-6 ziLD<5eUq;{7vSa(lH~~#sZdp_O{JiQrpCM_wx&LOA(LE@GLHX;&9RC4ED|L4|76P36!L7B0J1 zb6J*LQvJj;*O@IlgnmiM1fcqAQv^B? zUtTvh1*Sk|!fjo3h&)xrgb*0O6(9lOT!L@deD=_g0JLMqrXDQv0CW#%+Qb!ewi~(TdbReaJ z7bB*f!iYR{rorI8@AC-h^FUup{}8!la#GCL@*sI0QJ6vMR7cT?0=JsM#}qxt9h(Ko z1y>MEWhb2}6gnX!{ji2AzCic(_*@_ICFuDs<7nOq7{(rhl>5`s}Z78k1hEZ@?A_{_P%Sf|6)POS$lud@1U*2DMB=rKXL7DyAJe zCt;Z%)z-S2YNX*sBdqp$leH{CSmbcb(3=dfIcOxgGf<1cGx$tCSR}J?tejIz#h1MT zh!k6yoiPcHz9rH(%fBNRS^tqNi}f6`Fe{KFwG2m5qU;H|fCOD+{oDvqT@Hlc{WvoC zzUBCH7T9k2W5$zOn;adYVx>-5^qNn)N9M8e6c3E7K!0m?bL;g~`l5R0z~*>ivT^rr z67GXIP$J^N3WEhNK(N5t8R8AM!|e0bDduQ${1ZQ4)RvS_EGMBt0Gg>Ck9Wl9FFD8i znXr1QHVB^S&)5nMO3$NU@!|1J0?fTYDu#JbHf309{k#11a~)<#BW?DRa7vVk$A(~8 z%#vysr_{g+o37YNg($)K^dm4h?1|jo{+dqf@?Pz=hNJuEl<_S5Kue`uoHF%wJ>x$_ zAoGD6w?t0G=D+&kM-J~!KIKhvT%gNhGe`@W+lL++*Bs2#%&a`%+x1AVC??}KV;~Lb z|Kh!_CwKBn5aEwWF^*60 z?ALK2?aY5y3_)1jSY19oC|F*-MMYArcEMC(g*7!bqaC~7@v%#i6eIpH4|?UF9O+%= zN!(Zj<=5hFBo9+C?*q>kr~Eqki@|w&@rm!5aijl)@s1b8)_jMpov(y$S6?%jrV!_C zgSysafjL?`&Xqz^(m*~`(OX_wC^LduAWpz*KLZk1_5IpAuV4I=VQ}r)O83~o1;ykZ z&T+(-I#?`3i2fugzG@s;0-kQZ(<&n``<>2T@J8YUvU;UQRVjS9Dj$`jSSTD`Eq=1h zA~_ONOlWM8Bjnzo9z6q;R!}`iSUjtOwVAv>Lc>^GYTwH(T+K$x{^o)rGR$(BaS(V~ zUXiUhT~cFI*>{%DbeSg^q~A&mEf6Z5kPOHz6>6O-mP^(zJeA+G@~^Q0QNS0rsZha5 zStsz+n2q&4Wy7`-vN1PD$OAKh4`o#mE?O)E>;$>gJXp93uKDp^?4#4<#>Ufw*2BYbh<^&TB6_Y~ha5Fkyi}gLwh&pRhJpaPeW9B3ns=2eg-1MC$W`a$%qzY zQ%SAq{q66k^XhW>oU5xX)Eqh0?yskq#p%RgXR4sh5MUaM=^IZ5;)CN-gA4qTrBQ@j zuq+Cu>NR(}uoRc86q)$=S@YuNy01GOc&hL_jf+bv z*u|FG8#7C1s*-Bi=6n8z**NKm>em^9oPsy-r`y9p`^nY8$KNH@U0gZRsLa0x{ybaD z7a=+yR)^kVGw1Wl-kJ^KMI6ns0Zj}&V6e7Aj_eHXC#%&3QoIb6J* z)Y@*%d-F{OyvNd!jPceJV%4&k!g*w&!+V7=PSF__{}|PiL3%TBh26j1d!RlboJwJm zp<0Qdmk)qZ1`@7|W>!dCt1_^n4(+xaGnspDJakRTmK$J2o&Odm(#HLQ~z?{}-qKeXM?x51ksidLq=hxo1nO!RhZg5aZ_$Fcw9cyH)xK{5cSH5jWd> zq}^F9ix9?1X#QAXG{^;k?|!_C(PIC4Y3_*|5cgvKJ|UzKnYspLkf5R^6j)q$+{A^m z<&fKv-6T6sZ62np=#y%OTi)UoKbhT}@3WNME*Od8B}FTx0d=xj{P2cOgb>9jtZ1v} z;glCIh3-U&S~xq9aS1i@-T8uc=a)6k4s{n?RGSNLkKkieeGdFL8>~!awG)XrRpR%l=pG-Wh_PQ;D>DB0){*^AXi$`$0y?{Zus2lDiR0{TrkIAe)ar>Ko z4(wncf&n<|pA%{5EeB32C`}zhV#-h^YRospqQr@&)sKqvotThvDG*HTXigQrg7nkE zJ;}XEUAz#Nq+u<2LPKIH6m&$$Ja87~%{ga6f^D3iV~uZKT^ zldJ_8<9=W0XH{`6A>LzQ!$Jimg>Sg&$U@Mo{fe`4N|p3rlOn|5lDMoH&?^M~DRK=C z1Vcv&1zjhgHI8{{U)p7<$b#epA%IbnYyZ(Hpoqi!CS!`vJAGKK5n^%5lDwfOctllHB zwgn3{GT}fZj zKc$HtU2K8i*R-L>fySy-7CE-t54ft{V;NV@KLFUYytS4(Cj>PB2l;@}1<5P=h^vF3E=w5#9(Y-_6zw zm~XVImqJHFBY_+~8m~rJL1+X~MXfsM@%`e$rcx73)++lD5O=1neGrVF-k-W1n`_{4$7FMCL`1--R~ZE<#Rx zsNvubttir9%aLeRHXtXJ{@l(qWFUGwj*CYoS*z19H1ME9F{O$pO+3Tjgkix z0nh^iZGfxEO$M4K^dB}8pb_M~P|>E7_+wMYh|Tr=nx&(YA+KosoC_g_wvF&sDA z3W(VVAjB^D>!1FUF~KB% zCbU|x*p8*%MOoT#BcV;PzS-n;Q!~TfGqnY3;l^Kd6haLnTUg8W8o$mumkq#D)<-Z1 z#b$Y`ZiuzC`{Ox@^z?J3jDF?67^o+nYoPi_{&{fgn@wCFk;Di&iw3JR#z6VAS^ZD> zr9#_oxyt3m-&Wm7KE+x#SA;ZY)qoyrFnC~ub*_=?${47In+PmTj0Fpz37y_vwDYac zEJL7;F6gqN2LnA*+`JvV*7!9|B8g)(*<^}bW~qr7x#qanpAIz_HiK^ZTll9z85i84 z0aFMcUMWP9HbXrDu`1+SOi;j&jXR%(bMON>>SRoGEwkFx6FE#mNOM#i*yOs(0ptqi zIIphfhWq2sa(RV-%HDct3*%Us4KqNCFZMHoG7v2tI0kGt$(qze+H~Z-@(_1>_(B{5>)6?*yjVsvHHl+tUD0 zuBtzu}W8ccINdZI^MmlJ~8An}1*nG9#sN50L*g?>rwyMSNA5X{k!HRp8rY- z!ngW)RKrS2&3wr2zr!aEj#S>q4|J()H^&M@j>K4X z@>L*$%SHn_Rbh{TotyKG7notG9*h!Y^S&0Cl!HQGtCKgbTQRCq*cMGwppk@8(Qhj_ zRjFCgPiphOxHKN!tq;{6?&_lbJGIzG3NN(mv=XhOH@qPB-z8^9rXI}-;!q!G8DTkZ z&+ze9hB_4E5E)BcOi<*v&~FgA@zg%fEUP+$n#3l>tbKWo61D+=0~Oz7Q;TNhFT_Z9 zp;4cF<;qad8zLZfmL#D~1z0)X-ZJm#@1^@2rO8&5k~>Nvb_Uh|V#|m3P)9-O6p}zKsiEAF*78_k?334@g|-B`t3hZa zswzRUHV)uZCnZS3=bkRTiE)biHa*XGVFy%5`j4ZN93C%D`bV$$(D%4ubq;b6$Z?R< zUDQ9D3KUagfv5;E5ZaXO7Ej3bkM`H2&ZseR)+dKROz+fWEvC z9@>LfIHRhVZhB@LMmR9vcBLzX4IB~z1uHyE!I~dg!;%NQ8$S_aL$oU8|7Mk)Qlv8g zv+sd4nr~l;tV36|*^tmhoK1xSnD{vv?G}P4nUyMn%A#hBio_}AYGYG92)&)f06hL! za!KTa=kanoKfR@l4r)Z(2wXwRBSqW*@-v1PPw0R1`9!;vtF(QwL)DDKvYi&BeFKGf zUTB?)^M)@i*K90yD+$#5s#q|mGV7FV!zLJV#fcx{aIKqDpoSV2QlIZb#E zIh$VQ`nA#!d2#MDYbqUbf!-5SVe}k4A6u^qNk=^SM#!HlIfK)y6_0%;N@`ea50|UN z8M*uw@?FF?4D{ox%OC96PS)qOOi~(1RiO2*EOHbErg4pm`=VI}+%Ayr#sa1`eg~QH z67|!zRf$>C9I{)=L786#XlNBlseV)oer!SBaCIQZ!F4n#qR-YBv2NJFAQTl9lNK4l z;ZGULhy0um9c6AJ0$q>G>2ZXjf3Z9R%4XHmM0(XErit=o% z47?T)VC0-($GI?A*rkFN0k?BFo0G$&>M&Q#la>)41Wp5 z{m#z6Eq=y*LtnB#HP9k*-t6|0#QKYXkTKH0P&iuf2-oX{>zJ0APpXwggYAEHjGQN2<#vsmYU;gN;jq3x+Lxq%NoIHMui}nN~GF6qB*_vUNM+Dp(di>!wcz%5?ug62vkeNcT>bUoXv9N*ZaA)wF3#9H(VEc01VNd^|DD8la^f0Kc|ei!%sb{exSC190755KPlcpwu={jpAI#pu)i2J~ayED75M z3;RW7hm4NjSuRsp{6yaE<7I2;+vqv(;ObpVD^nYi4N1~eyv|s_J_)|JzQ;^lS1d{P z@zj}bo{O#&{ET|mCwecfr>tAhuq$@W+R0DiHwn+juO}GcQ4=ZEjY-IkGR&NAk-C^HD+f*kxALvP+(-|h&b#_dIDpoJ4bz&G0`slC;I7*HuiPKKn%_VYiPHR zeBx2ctc4)>`|Y}9B{>gFaZ8hILa94)jbPV`trm%VwrjVoxhK;7f7;o0x5I+cZ5>H5Bj#-Ct{;*4y^`=qUH#j{e#jU*%_B90K-$MBI120;i`XEq zzl#!lnbg_zpoSD`x$(bW)}j5dT~IYsD(;xQ$#0+YOk#t}UPdG@sxn35I<~xQO^rgs zZvAdaTh>zG-H6`_l5I+dAyxgcrlW5aMAF<+<1NX7nCk6}d1$8VhDcd~+MpU?SLjGo zWri}L5;oGVc|^7&#LXOEE0XvtRLbu)F1({V^5LbyL7Uh5+PJbsvS<*JnNUr9W=_E{ z63jGF+n^RrvQk{XU}Vwd_T1upCymeeD1mw`du{&R;7gQ=Ed617wsEPWVx+=o@+-j^ z@P=AKmx*E&?!^fyw!*bimLBOxveNo|l%$Y-S&gXK5)lIjGVNh|!K}Y*Cru?eAux*b z&B5m$h2t(WNEM|jowEkY0a7&cS$d$!+JV^fOyZ$G6;wok`qQCR0@4={OktA6aU)|( zNS!oybwc?nQI@2@HWNz|A24*xsgi!a4C`ye&vOO?yR|M}Gh5`()ujJ4K63DqAZ_O6T*X z$9X(z#%LF7OB3)*1`MNMC5+S)BPs*8&$!jCaQ*5+cR50I`SKBU`-f_IK|Pv`C~i>b z?9B6~O*rB&5d@4rUa49|Qu^C}p63}a03lmQsDl$invB0h2Czl_rXhO2LK~cNTnq|>`0W9eX+|2LD|@` z_erEj&u`-z9rt&=Zh?-`rCIy6O1}luK}ff1f(2E?R$8Y~@ zXh8R`AN>D^273FUOaC=Ap#R^Y!K4MAENVzZQ(5U%J`w^SRWH+Xs`KUVp|*4RRkPCD#S2{Yv+@(=(H6%?&qUROiXREM37f@3ymLzWANSS0qbw|t#zdjx%FO{S?wCR_@WWctR#n4Ht*rHW5uwK#B!e1 zWCbyV>QbWPv0DH47jTE@wBNPDY%^whC9R?D0 zb{=rN-1|bH3W#I9zJR*I5RdNj+udWX4}ledrf1eA@!5P63UDw|NXZz=&dw6PDenrg zt9c@6SF5*ulwZucp~pJ#!3lk&zJ(N{TL|wroZ}hmt&0cR_n%XU3jpi zO75uiR{@H?5*PG6`YtP1J$%i1;NvkIIlsxu)6^=0&Y7HL5#zqoLOvsuS5l5)Z&fh? zlvU7TFo!@3$vI1=G=ix1O=}z8cB$XxZpq~NVg4mGDb+vKGkw0?vMtaVw(|zGmmiR# z>zZZsa^Z6?MI&kx{S`q$_-ea^D?$UID$_&FPNI2w%n_J0G4<9FA)e|}2 zZ@p}ByCRPq*ZQyMWrc9`5IA5k5A`bY;Pr3{(BC@X#r}N+wI1DTtmO&X4cb zI_t9IZT32eEVXksl)y2nN#pbca#Fc_Lr4&*`vQGEVWu530~~x0WfXFbZXM_Z6SJ)= zOXQ1sh&+?a3Jg97+FcY`HdlNvPtE|C$V_&5O>FuUAV@soI21qsI%AR{p*@pH0X(2K zVE|V6WD}YzgP4_Q-~Qd3rl}vP)uP( zOTZ1NCom=x)iTjYf#T^?d#e3~ALPd)w!@y(T4epuo$TFd&0D%%5cAKHl zR*4#PlY+g^46=fa+q<*q=^MyJs;0m!R-5g&)q;RVY}-%=fgO%C$#@K|7nmwnr^iAs zzfc$P_{FAlviGhHE0nd7HL~zeiUe_2qM$;bf*~rzQWqdsP`l345k&jJQIxOQnXtkE zC^jWW2z)lI3kt`4eHZF2LE_-ES-m+a-G**h>x5AznJ=~9Q&MCW+LCx>NXqa9^iirs zS?sb{hGF%Kfde!Y!hn5&L!|&$OoptUL2o)iLPZ{=3}h%js9a}W8!W`6RiBh1Rn|ko zU~P4>CGzecc5=|{hMOd6)1f=bo>gH)RGfe0GC>F9epx9ZLi=-$gF7*S0?!+OM zyqGg?1n6c+HD?(aR%BICICJO*w7UEJG_oZep`{lSkvVbusIq+iz?_ zdqn$aoT#H2l5OXXS~MaZHXwvyJzfFabuk3HO+EEp-6ueFyFs_pQv!ix9F^2Vx#wMz zK36#Qh4uBgf0xPLHyZqH4KK!pXfrLCN`A`_%(J7tJ)TbuYNO>Eo7P5pHqPTe|>UENRJRb5@H z_ueZ|G54ibZ;BpMD6_Xmq zKq5H>(vr)H)wPO5&*j-n-N}fFht3MWwesLHe7a4U6u|a3nwgv<=9XlQ*}`lC>ZlpA z%B_E8t-}$hz<~KxvN=~JWQn>!whAnatg@^R08GCjgQRx*o1>ctjt5Zr`;Xv$wH-G; z6xVuxq;_;%T@v9Qdo`Z;!IZ%$$ck<4c4Z+9bL(>AO|FE}HHQvLt9mQx*_*l~yfFuU z$CZ8{vqp6suh;K@hQLXa*NWLA5)Av(V(!F5<@azH~A72 z{+0^re($ue-;L0CEGiqW=F1hUVEp^zvX|$0Ir>P-r6CA2b;`cN z$4q4kzBGn+)ZUkE?LPUNh96f7VA0Bi*`701tM~Q`4LMR2IJfot7aju&s~dnNoypCT z@;FqHO9uSt9c@xju56%otsnj~O$7VxN)ggs5kCv+=$k1{$C-tJeS4T2J)WD&6~}~? z=~(|#6ZLIU8mV=$#exb}N|JJsc?5<6v8)+tQB28gjQk`uG)<^B2{Nny;M0(bDpn*( z6y5L5#T1yK!&MO^K@_{nn1&@oe(RwwUga?`P+*@>r{17y?Jr1q4*u{43K%SU*UPSe znsGBZfF*$*=4T5f)?oZ- zeY@a`t)WsbbsJ6-Srx}1mJ_0Gqd*ih)?g)n&K!}mI-3Mo92+YN5b(Qu@K6jVGp=jV z4a16PiYUGJgZ02&47ahXlY^_Ht<%%Vv7VXEcm+?f@bryUe@uZ?y-H!TKm=biA6l-# z(=optK?e<^WR3Cj=Jx7qNs!@$U2_}+iLQV;H>;xHet+}Qa>Xy?Vef)a6@lC)ZZV(P0%e!Wsw-6-WI(zmMI#qmvvo$-3xX)Ei{FJcqt;0^ zj9Lpp_gTl2#eP)edzL}o=)|~fxrCq1g@28@kh_VC3)gX;^5#k4Dc`{Yd#P7+cZKN$ zmqji)d*QJAn!_jEt*#KaZ071r;OF#si zE|xqN;Hv6!QMT^>u^9AVgcbE78&E09y^(h0jvy)D?+y>U0lorBA@A-GwVrw z9KNC;X#|od+=L5{|0z%}>+|?)@-Ix8!MR*QoR30xDv*$#q#$Ld{P`ophx^yDM-Cx! zo@ZfX=3lDDM*0Tdj%spv)aaJ`J_f^VzaWGg%QmXe)%(Y-QZ!Y(Puj=^1FF5QM+Md3By_b-cM!5L;cF58 zz>mTtny0c3o1pCe5p^n+^J{IN>)KmX&z#U;=+B9pi@@Pv11r%TOZR+Y;yg`I0 zQ#%6iZy7J;XV;h^EZU+;kUHX+Ub2Y2p~Irh3m&jsHJ?iNPXbIj@Smyuv)GOMXT(kr{EhC(A zO%#Mg*1?4U4zSw(J^yl6>J!ecmm>IK5egFpINp3>RyN^;C~ObD5yjS*^QWima;FeO z`$Y)QJY~&0sLfURUXdveB|{E{@9pv>H^t|WLWxNB#JuvYYVWvMl1~^zP;3V^rRU5mkzYG55h@!!#irlVfZ_|}k>_7jTj6_=pdJ|T zko?&M!1+r6&xt!oE-|ba)cQN$EipI4Sj|P`YzY)#)c9~rgQlUn?qY_Cp3UXGYW?br zY<<*4iG(4L8RBvzvxqBYM~yMwrnj!bbyhBacu~ypD^yyAAt4eEN}ywodn-75Aa1Mf zF8WtX{>+u*Yujmrt#007GIM7gka*(0g;J5UpwWy3zjed!kB^5BZ@VWDw#Y;QMCd^i zbORlC;gFtX+*G(fd0aZIOqk}}_ z?$9LRRj0dE>xL$7<6d|e+OQ68GfxeXTf08c+7b$N0bFb7rN!8g#%b24JRl+U9 zk#(^ZKm$lg5Kw6N-@n7HAnD`H1+hQYCwjQg3vhOe_D-J6WED1Kkfeq)@D5JwWnFbh7gkBe2+M}D@TljtpJc_7!wYpZrx({73@Y!$0 zzKs>TjBTwiANPG6y<0o)*EOM+t{spa!}NC5CHD4Pm%z@{X2!7xAKvwUYO_I(ORQ@{~5F_qYoy6JsMjJGAYq5zLyDxu^CcEROiU zO?B{}(g-D#EkwRCFD?^?8HDiJp1X$L(L$_WttIY`I}&3*%i^#bv09{#u<93zz|~38 zaCrxf>im16wk+a-)RPyb)c&FYsk1Ph&wS^PM6Kty`T+YO689l7(MX+nYbfr_iD&BI zUTvQ{-0l|J3tN1Zfy>D~JCoMYP_E2Ga3m@BTCya>ybo;UD9@K<{1Zb!HI(3M(UiM# zP?xWdY@wp`Ur<-1{!u@@uAY3jcV9WeMj?KGJ+_Od1qKZ~>?dkXilr19wN@l>CMEt{ z$U=Y>$}%xxR+2cEyNw_Hh1qjyT;$K3N`P%Di3Y&vGrSE(;3$ac8%|i87;B}#s8fYZ zK{4G$Iff(DtYYPK;4NFzZjt2OLi-Kx-gqTr)xiZ4YRscL+0UJh`7o8Qk7`mCt6ov1 z$Oa4$)BoGjYSF~Ify2SF(6NSs`~vYMe-g*cpl^Un?PKRaF^WUWrht6SFN>4RnH}uc z(b3HkKA82J^?iTgItNfSI&|#!YSP$cXs1q9E3h)CO1d;L7T(gDG9R#-s|uVIk5&VO zisEo5)y4MhI9L<;uf+`?17mCV_+)n7@5!5KTIpLCK4UQ9jqnidx@C4NK>yHRG#I*) zlnnlETNB`x#>_vN09ZKx{V(gok_8h^RBbwc#W|cMU zjuBY2qE>ye{v{z9WDgEG6Vqsgx=SB%N&SC z#v3{WtQ5u^Y>z#e0FE-R&~tG*q^01ayK69?W;l+r90neH%t0LH#aWqUXJvD~w+6`*_F|5XJ2hDl6zD zw6sB$@1pp~?bXMLB`~m*`-ouGwltXx({uE6bWCqnnD&JWL2 z@K;l+d08(DcMeQaytjW@y{j0B_AWl+?O8IQ{5H8HWr@>On1;S|?Du!D?_+g0Sf*zb zjCeTikdXT-g|>?@w7^dkEGa!2)8(PoJat*qeHEFIQW}6wTHPt1;>K5;XITkj4uk#c z`tHz#g(a>?iKbWc`#-U0~Xb?vd|>C7%wh=CWSi_4Z4nb(yp|8nJ^xwGHv!j z7!r~@!T5ZmLCn^u73MPHHeqgmuaH7|Bq7Vh4hpRV2;#6n1bc85OKhHoFI9$7h7)H% zl|pjt+boTbfEf)pCT#APB&?5?&~&yyfi{*I3pYYUp&`^|D1_pcHD|lWn>rv_5tOFC z|NPlS(jsBip`dEcqfwjT)hkuk(migX0fNV~t?ov=u(h2IWS>MA0~|g|boe?K zYwhyZl&)V3ZBfVx62-r!CJJZd(7nxZ`t4qnE2x(Ixtn{19*H@L*Q*lkpX=^-zb4bC_2xe# zxAf3X2ndLd?o#z6BVk#C5pgRkh5iOC7Lfp+X8w2OT!Fcf++N%j8ySVg=;s4dqD_miFjzWW% zG}@!!?zO${233eAJ&QSA1Rl*F?dsb(9yk(kU2lv+TZ0{}Rq`{?1Ougi@N~in)G{Gq z*h($FCXXV)JV?_tAkZ``RK+NE2hnyC4gP9wkpKtCgXpFy>(09}D2EXhIb+&M|32+& zKfDejX^I33B7FKAbSR%wY*p0qlM--(7om%E zSYAkti@O943}}bygVFzzHH41XQsu-*i$WBdWEoi3_+S8Q{RNe-lX}`*IlO4+%f;W zN8G|Zyz^c+xQeF@@evE4cl!CX8}Vm!kkLOe5cZCL7zQQ}6~^;!)J!$De1%nNt9=bg~ z3>{w8e0D_A<=WVG-l@BpEXp2&{U3(*Vikyd4-^B7ahp)Si-LY<1IrCN$TR7ehi~01J8k1lI3za z2u?Mn&L}tjpg0O((?JBYxF_pE8=WatRJ~`rwHfjG7v985sES8Chmm$qH{V3FYQGh| z-)_riRZ#R1kST$K*73!NDm^&mz-5L;l;+$-_sMe<#M3-;4PT!ytrVTvlNIzK@RGI+ zvef{1Bzr2mI-46Wh8Mf@9I0vXo@!x99usOAnGCZNw4Ag-xA0^lm}kB9cx-inif;V_ zV@jM#{bfRDGN_6ybydfts~pQ@BZ~Pt-rQZ^QYj)QDglqR5hkR6ySo%Hs(F_AQ5B6H zt`=wtb>TUMqAtl>&_6!Td%iM_QsDYG7P>}>0G8@~wzvCUeVS&2>GAnIWy%sG?p?!c z7lx!PocsYhTmB?P7@=8AwZk+wrJP~BPQPMQ#dXG&6~){3;LZ~d)WH#ML^yDgvKSsX zO;DzO6UI=?wp>%D?u@V4ge*pp6&|Fhd! zjPlZ3peUIUxOStpv;6#yWbbH9iA@58RkHaJ}%2??a_v7i0ifn(riQREX+085;U(dnA& zM;>&U@=KlKs@sVAFZvqxW)ON{XU^UMY_oa57r4>cx=}j|HD?;VNvDLNvml~37m5h9 zdzT5IMsFTLx>)(S(RaT}AIoVW=1n)Eo`Tp~8Z2QJS3hl7Y>cT7hZ&kMHc3AAa$Kr1 z4qX+!nSY6r1BG70_O=r7aE2_mU#o%@zb zvrWZ>M7U2$;X~Q1Ek9D=Q#8wR5ae1#>z~rvjldT+)9BY4vVZuYW+`IywSUJEzrn%yxzfc;g_h0NGi;*mvV>$JV0WFyx7YGG+CPhot|hMkU8QOkWpZH?*e~| znwujc1NA7fX}I)P5_Vn*>J1rJCs7}2o-n$9EfNU@Qi7(%6>FqrM&Tm3V=(s4E=Z^R|46ZqRpp(9(zKDDJ35RVh z(X<18c06k~5spE(BnBc7J$V>8OpTyB1%~I%C`kPNsghy@HW)#EI8nJQ6dq7Je`*HZ z>qCV8nmd$!t(Ik#0$O_zH=@D`Q|~rp?4~3CQZr@4P_8ulSFvy{4Y$D;Bn7c@$iE;2 zwEyA*^#7X={A&^q{|OZ!|A!AS{P2N)GgibC$i27ug+DU`r$R!{V+_&8gcHe+1561Y z1DKFFs#d7=9l=Aj5DlH3)?2$FDI1Ps+u6(F^_f2Xu{`w{K6bq3Cvh2PX`%lrL2jPU zbxT$^%8KZ0sAS1CqW#`arOpcx$h8a`o4Nv`@3n)B$7*## z5Vev6t*i_C)AYj@;Qd9Tqc^T>@%E2t>i=}gvt->H8*6W~i&|Ml{n6=3x72irCMnpI zF>>pKNU8=j_Asue*F^Jwj9}V|z&Pm>Mqe*6DoDOY@Fx&c+W}vw$b@=e( zl=Vv!z82l4x-nX_a;h^Qvl^llF$5(7@rT~4AMm}j7#+Iokb<_}FI0RbjNPwGHJsA! zY=~oqwr$1=30gV~8uqPvgW5gsXeJACTh>+ag(_e}POoWYw>B`>IL=TI7FZnqK%DB@ z#Qv!E+tig=Q%y@)hFR@M+k1#{GgKysT)8A2wjI`%hM-{*rdjTwneYmdZJ0C9e2`1e z61e_JTqqgjgFW+$Ulk|3eONfZC&ym7M*z(a6#5InpJ8Owjrv3P=38DXU59|?F%n{t z5)h5d{2d?KT&c+TS+%t6nA0Uv%)BHM`NznmZad7Bsfce3M7PcmXLp) z3XHTnHYo&p`dE>wLz4VA%s5QgxyLsDZ%4u2*kI)i@5 z#Cc1$Wp$zegG^n;9^bX&Qx=eg7)MH{MqF9?sQ`?@y5KOa&z?y*>l=KJ9n0BU&6S2%1S3lgeHV1jLRTd% zO;Mf~weucUD1L%QD;z0Mi6I@=M=G2tQu1(`Da!L#!J}tyz!(8Cpby*dm_Q%KKOygu zaDy*{7!u3HO-s*LA{HflT#q)75a5Y1SU9iLVivi*fzNZ+< zZ_cG){zD1NsGs$GdEscFE{q+vWFcRC|EHD>oeixl7VJXjgbCewsuHuo&tT$or80`^w8UGY$ zygB36F*+bYC{Le;nM{F1fo7oMfK$Fc%c`P(f|9Hmpz3GD+*c9oy&RU11?TmunkhN? zd8i9BoMBS988W}*Di_+;fKsX-@6IrzMxZ?aOKkCMfNSH%)uu#;BdUAjDir)Ya#J6F zPzha2Hkwv~wAN!EG`Sj z%>~NE6Be;@z0GUgw=9oU;5dRB~oTDER%k=sCo4C zRE-`YmiV4n46eG|2r6McK$mtVe|d`TMH+VE!+ny=MO|t=f)GKMp2^uS%Ry>9sn4)s z;BoR*R*K_}8X5@5Y;K@tDv&9tbRx`)OTK-xt~&t)tJ#0FH%N=IFM6+wY0`Z8Ff4{M zsS;m}y0(#s=KCI^r(|WQmLY1blGXfb$?9gWysAnCM%YM_Djsu@(@aesFtFz>z>!*C z-}wxz`x7pE@d7Uv_m^af3}2!Xeedba(6L(=1%&FsdxzfV5pobwo(&{tuH2DT@3Tkf z6o$YPTPo_$6>AZI1AYki$&#U+8@+4Y%6IocG}J<+F>_-(A`(;*-6T2v^e&;<$$5Jq z)Q+O&%cvsVB(*ciTbo6nWN?}(kqY7hkh;WWw)$^H17{_gHPh?a7y_Kldi|TJ4X7%3 zu-(3ma!8*FsZHNna%0zE*$2@28S#1@Cza9teXemT^cAK27^#MGLTI$cl=e z*&Oz8wB1)(v4}x2g-6tkQyN61kuHXBN_0_JYb@2E9c9%CMEVCF6J+az6CJH~hgnf4 zru)_pN=)N5@erGWa5RVMKB*)n37$?yKYjxCDZ$p@Ms9$422Y zSCB}jT{?VpQ7g+1=5)> zcuN}9z1lepp@{*wIdnkGL)aXq0FG#o3(CF}ecjskKIHF2@>lycGN@tQ++O3fF_Npz z82#wKnMzIoU`l>T%t|xFIf7fW&h>38PBav?PRH55ph{$jcV$P5f<&woNSXIE9a8D7 zi^GvgXzM`8RsS#_bu``+V@DKL?8EtJJqGgph1s;xMlRc9nm1g$vavj#O~I~ETBDq+ zLS}&f4tt~g!}T0%+wF1Nxu$1U!fR%PBaZ-7uqE-zt*i&~LVl#6ZN^O8X2>e8@c51kAYp!8 z(EE1%D3Yg(7DeIJx|`w5>?OnV`+jiMDF|z7MVY~X@NZn^Q0DRnq=CN@Yff?0`*W4* zCx)P4-CV}WA^uS`VvR3SrMhP5VCPtI$dwfWtFpHc_60YAXbv1)rv}|^Z|iAjwB6i# zivuyI?Gv!{N%8c3TPg?=dlz&dR=y-hNe7KwUmaTDnz?;ODfqHQbh`mYw_pXOi#Z4Z zmB+?3Dspy0pcGlEG}^@N-dSWQTkG_~Cm^jTdy=B;gVOsbm@@pdiGt#36spA8`S-VV zQNy4&A{YDk%oLZ7g{h_HrWt(y2+sZ*l)~1XhonrMs+)VY@0jT{%-lwxUyope)8r^e zc7w57ahx<7_R7_#$MyT~H4CxT>5-&i`0a&BSX09$?;7!s5fBDQyS;;0X{&>*gAi-#k`Q_Ixje*x3N5fYvVMD?o{AGoKo$IY877eQjktsEvV68?&ZR zvZ`>L78O^mWdv$2os#JkmtA>^pECbWPck+M6L~ZBMM1<$;J3jfUJ9VZzvJ#TKSecF z=mS5TiTcxa2u6eoU2qgbkbe97(^E;OamQVagaS=jygmwv(^e>CS61J?2DC0b5WlW7?*- zcgLocdZK~_By_x~c7N05c-O%Qp=;vO3UY_%B1PomNL=GGO3+UD))+X0;bNeijy)mV&ZUYvCX=tKp-@Eh5vzyYb0(5AtSsA_ON zY=qqb_qEUYF4jb(0VEri-j}mVH&r93#01Q9_eVV9m3$Fo(Qq%;?(PF1=4R_=3|;Ax z5LHQ%_K-jNiv!J2??DFs@2t~5FF)z=RJ&$hI7U@XW}XW+al%ziwD70Qp)Twh=g37U zBBrn}Sfo`!AycyxL6)gH(kHTl16|mX+mj~!!kDCaZU?|&sB0C63;i|JZ8FKM(66Y# zL@C*M^@^$P@4cb}O{!tDI8Ir`MBn*=AZQrq!F}FY$$jyXc}K}hCqHjXUCh2D_rTbL z#3~Zt5nF0lx1z*k%+-{ox@mT!r(e#dK!b?VAei7LaUhzOIM~$aMo*<@S{liUma(%j z#;N++*#knOb-!Api+k?gydD8kn7p12GGr@p_>?2YK)Xs9kZkr9+6a zvs6d?DA{IsxVZSmK>UdIk+Q-QaiG@YnEwvnDnn74#Z~MFjX)w&Pf~yh3ZDqF>!J_P zk(pcVx;ONEAH23eUSVqK$9IUo0eR-2gEIUqIOPN_P6{vp<<9*0uMxpn2}vhE={a;h zs5s}_R7E`5)UsR1{TomYRR~B!- zioHCg?p-sHBg<0{UdkaZ9h4w0V^?DS=O;#Zd2H4G7F2Kwce|^5y7xQD7*@a7Zrd5h zFV=*bU~8-6!?H8oBMwKv3ymY5R-RY0XA;LFPx$DyI5O7CrZro3jcxDdw!?Kn4!BZV z&B3$yt0Nt_xyj>x%ncXm%o9ejkiO=dL$Ba}Aq2+%jS#pRzf*q@0?~gE0@MFR45W-C z0RD)7GY2?aO2Y!%<@yiP#q*03O9fDykTb3XMpnZt4BA6A^wo(#S|%i1X~ zWbGFg+J=X(#|T32v+%Ra17jR-ug~#kI5%B?=@M0e_4-v9T3Ic|_QLLeTzwtA+1lPJ z^$qSn!7jFzX1-M1FW3Awa_=Z2Y|Tos2sp5{8#cqmAtLCe55Fres#nVzZHNU{_6f)Ae@)C|+C^wG(~HUp$u|!NO80bC z@M`zE87aS+8*4#X@3nS%@O1fne?}@$V1qiM8ErWbx+5wKBy?tf zKHjo_+noK;dF@_$(;d>cip~?5^l?*zqb!{9AFMvR{6vpKd?t?tyUAVf znLK#=dh*-}j#uZ%)ovoP_we$9o{{n!cg^<59x9B3cxc0n7ZHxC$Hs?uLwI^7sv&~p z8W^+HC}jYLgB#bEw=Eca^()pb>FI57q)81|Ms>MhD ze+zYFu|d@hEMY(L2P^+5b;uhQrIE$oo^C9XUm~x=d7RcNGHE!COTCw_vQ?`oJ}hDH zR{Mfiq!WSVKY@n|NMGE)(WE*b!FvRYdCct06sb`A3vQgX`?v_zIW|Yn4Di@aC2WhK zz($fI&k?J@SoZfm`gWDt<=q;3U5|IdHWfpHKEF{X;GiH>`{@dvXkff8om_SQ?a zJjvR5J3&sp-26dYwNgl4aIB~#G8rtxCQ0cxu4$3h4Q@?YUtASHmd zrnZvsFnW+pm{QCoD;^O=qS$MMoGJ68kn{(6(_jKW9QNE_E98e)^U8$J-KNS~pn!yl zbfdH}>k;W@lS1~rLMOhI)U|cBx6o?i-J+4|+;d=sf}1^LXt?i=O9x8gQ)MS;M?LiH z>*OcIlO#eEI7lY3<)Ht1&8BL}(S*UdY&E$u!jd#7V^)>qWNU*SmU=KY!`x5_Gt6|5 zVW{+QZvcn`l##N#G5Lg)sQx6GmIz{w(OI;r1Y7ihvjyh$0kasZoh2LOyqj3GW_bb= zY1ttK$LM?1B2J~gyp9r~R49GznLzhg*L&uHYOMf`;)~6O8;LMO(j>TzN3FAVxaSyi z_lxr5UGSrNHiazhGFEuR({)NDX@L=E$aXIbb#KbFtR4!(~s0%>9z{b}8g12uRQL~C_(tcRL*zHR$cst9>A)FMFXiTsU+66Vu0Vo>y2 z)T+RaeS_yQrLzFjhs_9p=?hz666ckTI_O`_l26*-GVhoxxbv?9zO7|+KW&tbuVF0j z55^1^Z!Fzxy-!5Fn65cLl;mmZ&y0;xpqFs{Q+tQO%DwRxDjpRD#m zak=Ltx2V7NWPn&ycoDZxGjkg3w~2u?6vup~3lM`89T36J{lhufa)DES7&s4}uu}{U z&EeeB)(mU|K@ikywo>P3gQwH0&4&2bOG@C1apIr`gT%<C`v@ zMJTvyoX3{rpqVjhe$w_7-AO6a)4q^mhFpzJfJ@^h02}8(9^5>wR%yuyHDd4F3KZm_ zz$5!Gu=LuHXN1tLaE=XEVih)|{n3uObr@S0GyfvtY?jc_Yqd&#I&2qwYtCFBLbM~(Iz@j4DFr;qj zoDxB(>G3F`*)DeaAgzPGlKA0<^iN?OBA9v(VJwx+=9ANqgR1gAsE;~N9e-c~oql%? zDv_{EfEF-L@~-GI8zXV(V~NU#>z9Pr8J|$(CPS2G)LuuKr<#4@4J^oSv;qm18;vDS z(4wR~zOGLP57i}pD3GD->k!>>EfXeFYn0LnDZF%_NNouV+tsy@d3`*mXmOV2wW_Nb zwI8oY0BYWQ@a-%ZN>yo?l|~z_I1JFxPHhqc|DCQVx|LUsm;`R#3^~H0Rs3bhpu)}D z9>p?U83cuyQ2(ClV{c#+0YlV|5N~9rO{xFzK4WUo0EcZWQ_-GZLXg&4RTls`0Wagj zj*$&Nqo+MRjkWyM6CD&IW`{l(3Uv)k0@B2+FxHXrL@Hrf-0zB|JYra{Lmy+QUMS{P z*!#CYEl1AOjNX>FEcvCq@xz|2gT03n>(NthpRta=u0s5M?kpXXJ3cQj%K{mvIkUK6 zcoQ{^?jRP%aiMP0IBX)MvVb^jVs6RUb!~I()Y`GxBAlnmUJ0*#QPByBY z@tcgq`|lv3>4rnu2!xo#v8ZYgtqU~ZgXOJa3krx(L-v%D$|8QI$jm1%YP0;f^fom7 zt`1%=jz5)&+z9q2VOViJflU)B4WspD(3k4Yv|t*|j+mmav6P za7BE!C^ZhEK+VEo)w7yOzQdX+lFiq|vsKhlYdCA;IWkQoGs=!$nh`g{nSFW?*&ONi z2x}3sgx0XExLK5Ejya^BeYf$xxXLSS2E|Tr;C?W_UDYv?$-h5LGp$=XB#hb3rEiEi zsZO)xJnIybtq?wfjD4wruX!s7EzQbKjtu7-K5706s#@dv*ClEd$VSBL43(7zMD^2| zXe#N{gFa+qN^Ns3-pdxcUO2a|XllDVK&u*?3w@u6)!}j8}~F| z>d3P$`Wm2U`HDmyxJboSCi3`#RHiNCm=Bu*8G!(7hQYw^uux}ltxp_ZzR&W}d-h&m znwru2ZC-o@!3CyX?QEL2_-ZO2GKzJ@;!m`y+u3lxpcgfWMb4w==CKl`9vsgX9uT_^ zt!L9a*~c4A(G$U6`-kNZWkTj(06!!L;15t_!%746`z@BJP>6ISzmoRi89NMG29ztN z%`j(`Q&5!O(xXMTv&jaq4H{aA>=+hhy1BFAwnJvu$+(3BI!;SyTk`VEoM*BJU^WrA z3ho}KQT>)w!OoqTnI|8igNF!zyX89CAApl=BmkO*uP+oJKgJ?HYzT@_j~L3Yc`$5$!%a?|*iE#2Lz2UdSO&0Dn}Ra6QV?Y&`a({<RLSCKVO$gS&fWYf<4<9S z1f7hJM%JB!q(8wo(4cRm*CN*%cy^$n$;JO=P9enSwO+(HaKfzfhC;OyOKD~<0kONw zjs{`@i*6}I>EJb3au$S|0Wlkvbe$iEBSwfJB29%o;r>}5lgK}u`fj3@!rS^cGN}E& z^dXjrNNA^saaMbH=+}`vxz*DNYmg+q+W^&qZ_IL`hyx8WP?=OvLF>8h**CWQ}cqrdBwPLmnBXYbi4P=iR}ZETV2Jz zotk9)$!@N;ZubDtaPPmm+&JR?L{Z#8pp5)dST#LvGKnE-)EXu1@%#i(FnWVwuE+d% z6s$%+Rtl!zJg(&hCqZbkYJiv@#r0B90&MI(A@+1FII4J;$KV* zp_yL2zXZL^M}7fax=`kidousU6qx@vQ&=XVarmh%y#I$Ou>3HEG#$BLQYfKPQ_5xS zQa*EvGwAc?aLIhuy~CraNU+FR4FLm=4*WzBXoX9bzgH`8F7YgW`}u8dGDQm#ybQ#; zSJTjCdK~#wF!6-`y?cv`qjewiZf|4%eyMZmY=Wnc`&aS{*gtB6 z$Y!2>VpZOa{O5RB!Xj-ujD@$axT)}^_H&OV5FEREtF`?Ewdg{XAE@yoq$Gq>gTaY(Z+hvB3$)Blk zLez#W#xIlWG+W1}S8lhQphDqKmDy??=^;2jrLop>#>_K&8&(5h$Ln)z-9I_2MB!g1 zt(i$sjf@v76eis3j;;6Hac;kf#j>jo)PC_v?9&?#m=xd{uT~_W*SoUOTCKrE_CD z_UFpy$l%CU(-I$JSlOy>zqwB>$YKqkbfG}-{P;&PfJ|1;9zCn-X`&+h&B=s|xWfzN zCEdE}Zg+dq;nqJqr%>k?Qt8sH`CP`iV%)IDz<{B``Ne+REcwuXh6ubr^zG!TN1{tb z*4H037io)N5wa{*xxlyc(L{+^&JYfMBxzr7Er@1uW17TU7C_HT~tP7FvDnC(f%Bse=2mXK0pTGqa^&jCjk4q}~YB2<)~MkEDI2`jSOT zy6oy7>`*y@6z?%~!84^z0ku`jrV8u0VI)+!7saxaP+6Y3NWHGJ9QC&icgcT`pY@ha z{#^RYs}S*T&XzIeVR&#xzZ0~6bm=mc`5W94m|e3i8~tet(|JOqPt}ch0Fq-CL;%$0~NQ6tk9?AZiY3Wcxby{FD+<^ec0#PsZa|>g|N%d!|L9o#+ORLKu8me zaSkLN%V{^F?I12?3qliw`r`e*dv@UBoGNW~sp3_${Zd5Z2n_=P03Qo*cH^pY29(Ku z&efCba6;C3a8R*D)h}886{$;GC)i=6pow@6s+L7SFEyu^*i%Awg=4<7Iws%=oPWSV zNDeW(LF_?%)RzG0Ibzh0R>86fz-Ox$lo4Em~Q>z`u!bi>0sIW4Y{u$*P10V7+`QsR&k z8E8}u4%~Ra1BzAXaTt*JoA?55FoGCykTbNbaBKKMUu)Y+g{~Zd{q09|&f?wxy+Cu_ z$(d-C{QKrs0hR+??ydY4%~G;bV{7^-VO+)XIx2MI@we8WfCn?OMWrRSx&c zVPu5V;csL5_3i$o7%%t))2L#0ZPaN%^LNGQqVCFiWc{s-5y1rwMt0JeGTs2i|0Dl1c#kH428hd0?6!BZkJ^V{Q;IsgOSZHseg`ak-tY6;B>2o1?yxBvSba6`|+uj z%ZFvj4&YPMo&=^(OTZhjqk!J*Lr#6Ud|FC@7KOaG0yx<57(*FUm&+)h3usTnacl_W z%dpX9Qp1i67LkI{@AMl>qQ)h#ZGfPHg4$F1v^#0D6ykUyDoiqzZBBfDPD)~9O^y|d z)<1mut(Kw}-F=@;)wI|UN9~0Laxmi{gnbY3)f=|eWiG~UkSTOnAocMt0DfIm>&>U2 zQ6N1yJTqUo>22;(FsZCAv#%|G@?bgp-@Igcg)w((r!<4TFS?2~T-)#) zY}>YN+g2y(*hVM2W7|&0=-BAkPCDq=c22(fzf*NC{)<`jZdI+SRjcNB=6J_o39~f} z0>mge8$Z3;%p<%qF(J*v1`P@ww`5rYix0q9S)!b2VJ)8#A1Qf3(t?-}A*ATl7Jz=i zmmT&5Db;lN6?IUs6N|43?1ti0Jz;J_^oQP1KaCfY+>&D%&O>nVq$&{BSEUEeU2j9_ zrJ12$D^D!I5xgq_&VrRlop`nv}3rXBoFBditkvF#_AX55}%2kdl*!n?f` zkPK9+`-?M^hcJreiqa!!vouAZgu9NL&^ilMnmcVMAzIM^eXE7LA|3u&HZ%iH4wJhF zH*QYmuU5G_I7^kbOBNdH@^t;X&|D`0&#;zVV*XBs@8s9>qv|Wn46@)}a5u;^RR=H7 zMVTALAw$9~gYaq2WI`}iSfu=y(A}NFbzacdZOqCC?l-@24(Q*o-q%Dd(#Y{uBR5Yi zB9lQEBK{pn3jl8XUC+nY*Pm>g4O_RkS&Ug7Tdq}BQc_a3X70`upc}uj(B}pGeE7A^ zyz7@0H4q+;KcH({9U=dxqXR=T@KM@?5<~y}Nz$=^9Yf0RA%*Z8%xuTF&sI={w2o!4Ugzrj7n#gfCtUuH$ zcOj}1(_vARY$U`!4br&mn2gFAh7)urAhWB8q7N?i+^e&~hwO%a#|Z~bDKgCoa^P3G zCU)6$Y!6&apH%5t5VkzEbu2pDMo8Hnc~vk^C;A)?S^(Rw-!G|ztDVBate^lkwD08V zQi}i!$c-o`&7Gf-@a0MFilbr%++suOeG~*ZD-|!Hjjla;v~$=&UA!)fDpdrns$CG* zrV8}8;7hO_-^eqoDp<{Cq{R}oxi2?Y@L#s9u@D_fmvj*>njb4L&iY|$G-+qp$PZ6MoZ+Q8dh79f6z0Xg;mjhF@6;;Chw&DY zki9|x8ilX^mEv-MDQ1`rZ<@IiTJna{YYx=NuVm5&f;F9vn3X2?-RU=xU@okE0vn{a(NbOF1#0 z*SjBMz+zmww3ZX;+MTGfI)350zw^Jse@IrBvPjMRVnbS)+{-LAIucw^li8`Y1nx+c zwm67APC4Vjtv~}6nIjSUCT_69Ex^AGt!Tq$f|-20^zLM{NnVPYvRUdS`)bm(k)DaQ zrjOjh3Nd0^j@E5G-me15CVxcCnzG-Y*Bic?^n6~=r#bJlMBuyf5$G_w#ZQOQ6zk)e zY}&!7y-29Kaqh~mVw<`7{aJ8Gp?$51K+N6!R7h;yZZu)lSTF_?4O|Ky+VCfh`g?d~ z45{cFEfNJTHT?$wpGu>Z(XL||-GWCk{LIp0_gnl366ah z)8cjqA()?qMEGoLjn+|BERvgYN~kZkG!Jj4I}sX5ft^;uNiL`8xUEeC`9IN-_a6gg zb|$ZUN&V+kEh^anErhhl19u>UVx@pp#GT65c6ZQNsgR50@ z0nEEGO;v{wSrwvb6?fESM4Hr341@zbkEv}ZPlr{%X8WZ_60*FLC^38(YMSULQsebr5jcgi$rdSm~GNLtJgkaIco|#qruE3?2_1Oc|UHX z-x4SUoFZK~l?3`lhtq0l_)F23GQc%uaZ?kLqILFeciO-0@jz5K$6tFrK#;RbtVoXD z(Kenyfx@YoUOPdTBdC?ALxQbj!j!mHt#t2qC6mA$QIz!gj(O6jExInk1ELL!2{McV z8ij!yVvFG+-qWdkVnTDzg{vrY+(Oq(|mLiUB0D2DX;@QS3aE7E_%HrvEwo<>B7tj5$Kny&V z94cj%b82423&-MGZl*e6X zz4kHGk)R52&4MZ3j|MLyB9>1Gt9DcI-3j-!{{ss+{|gH|zjn2+g$#fISOCBdT@CiW z3N%P(N6q5I8&xT91k8 z^yhAz1&3392A25_vJC#P7*7?;HhTBtzry_%uCioGPx#|Pdpte zL&!SUIp7@I z8Eng$Uz0O_Sjj%g8=X8}qMMC`_^fS;?akju26n%==<;BYZ+Cr~KT%Oyh{Jm?`F$tI z^R0G#snB{A#iCBdT&;HZO80@lpci1(y_G%pa)0y`Yk~Rv_3sT8flZ0F-A3vjBsmlz z3D+R_+T1l;dsO1bjq<~tes9cQW`7nS7Zx3F^L($UtHg^T_@ z!nEZID<!)P^=^rieuxLO*d1*H|m@R4$_8M)}yStlM9C9 zw~OD)V<+h*1uDvgNAADS@NywS2B%7M#>&?NZ02|b>~gGr?5qS1vC=GDe*dw~OhBKb zfc@$?Is=73vJP6aW+;IMzzz!~QcOndwH_AD&d!>!;Be}{U$e+#6lJK;O7ba~ItVS< z1#Yp!>$h#WPIu^{N7|Qek(_M3M(}IDQIbSSROhgpC?pb4Ea4P!s)N)(xvUfcRF_WJ z#I-WO4h-fdZG(6^R=Y0$2?I{=`iYDTj6_ z%%ajIg=B041+{=Lc}trX1HYuMpk6*$E>yoIU0_Pm{mc7dHM*@+ z&-mvzw+)0Cxjm|wbi*T*>$^67C^e!cKeNjR0?FIxN^E*Rt+*-w0rOL?Fwt-BS*?2y zH0Bya`C+x+Qhk3G&eqC#4gM@DA04^kLonSV(I{Mw*6T(O=b)7RJfA%L_d#(`7SY|U zBA2PUg-PbPnVEs^Q6*;~ea;$RO%a4_Bz=B6-neZdEK!s}<<%?87X@vb2#EJH?q4lL z_gOnv;!Nq#R%-A7a;}ZMszyPVJ*<-tG%8j8KwXkK8k7gD%9?Y~myL;61gdSsi7gO5 za*TOKgu^Xi>#yi3_I8!lO5ldUCT`4Bp*EN;+jog=jkOh*n8uAcVu>_ zhBy9?%(IQ2@Z@$+)vI!rAf^`~c#)(MCI~yREkn`i+g#{4_xqRy8<9r?$2D{q%~eP; zx@LTts~4OQp4mBQehR0^HHtj!vlW z8})=%@+d4Y%V|EjLd2WZfzW_13lX`_Guelji-7V7660EBuH)QXexJaDsKX;byLTip zG3BQD@qFU25Oi)ssniG^WaivYeMq3b>R4^n$lgD;X;s7PFu)T0y+2p^Y)iQ?0AmsZgP zpciD#5H{?pG`7N{Cu zNL&snZC|nCij7K#Hx`?aX%s+8jOt43+oA3|BjU3JRm#~yrqqCMjqcmb2R9=k_nTxa%^da0&d2OTzOckJv0j{D)YVH7+V79=3g z!a>h=+GwyMtZwy$5?7FGMe`iA0wOpbB|F|KkdP!VcG{TYBgaX``jdfzjYEVGIWd@L zSofGED4NP5tKQhTazz=sSi%|+P!D~NSePOTyWwY)0y&>=d&~-=d!LrU&V_ai+N z90R|dy~-s1BwCJWnem^>J6P@k(Lg?}F@_F=kXPymZfJKENAkumpGAD^ET#yFimD&) zLd-@gqh>+^0s^kQZ$Y2RM1`Wk07>vf_`fi@MuiZ#r4jIXGY*QHy{CIhA0>v^IF6!~ z1xSBxn2*GgH)qs`kc>U&uU>#+S!(NS6AUJZ0EiJ%J~R+?hgdy_WfjEqb$hv(%z5d8 z!n3@|BNCq-XyCU=Kd_4M&$5RMHhegSj?|AXBECcocJUesdWx`w5;xzMT5ybt)a>Ut zk=v1bK(m(@)%}SLB8Wwdk)OpDa#Ts2r4!u1PJpMk5J-N664Y<-S67PTgXcn;zKHdt ztinQ>5ZLU>QVf4*OsmbfB>-x))~8oH1aQBF7&RejFy$)7s6r2hGQ^=OX-V6%aV82P zh0R!rR#bFiR|JTPfqBfP(p8Id7z#$KMxTDK@8uWnX>V`u>}+7a$SK-l=PZbWCjy_A zuSBil>{qKC?vp(m)J;X&Gu&~_X~5>Ph6IRXikKmxQ;5PF9DTn$xw{He3dO_1xM(C^ z(!1N^lLqghH6QDQDK*%Ws4J^p5u$^pgISV$*5)NA!l$n5I@hY8WOO0{dWO zU~fyWF5>U8&4^2rTz^dI(ynS%My&K5V(eZbeW!)$Oib^i>YA1f!(PX;73su%YbYm# zks~Yo9_9d2!~iE2!4+e;y!d9^0Mz?UxC{@{dX*ejH+p+7x`G_^(ByqMzP)}Y--MPB zpSOS!>5gToGrDt)6#@e2)uq#XEg3#eee{0Q|tMMDDx`LjMO^z(T zPz*u~J}Cx{u_2yokqB9SNRKt*g;K&@O3^)XloRa8M$ z(J9nxwLsc=h%LpxqyFQvX$!)&#tMi&Ps~L-YZRI(=(FAJ%x{@c{S2me=|5Zwn!%z@ zc%RtpP7eA?bLSoyQgCiLk^r^fxpJ?=4Ghl?p?t_G>5kJ>;ZJh z9w(=A?pxMAJ}0UC3hFgHz^@gr;Ak!Oh?{4GfuHTnns88=ZygBV59qoc*XCXM|qo-O-TF=E~QD563T-nEIcNc-$3?O(ou8ps3gRSUa;-6>Rc!}bA&DFQ@~ z?~^4GaxnIta6go<9%I%#Yz!jG!qw^Ht^=jAeK9A&Hs>XrS&?qXHo~ErW|sBluCyt@ zN?^)TH0Znw@Q_|B#4n4O4D8wfS;D3mb`HJU{jX|(vjPM9Z>6UG<}?hIbr8h^gNNKt zGzKMTQ1-u6uGf38CTvxrG~0KKbpJU5f2!4q32m_Y{h(gd9`jde=FE(E5a`AT=J@44 z=M=r|lC<+J6dFJNk=%qG$x*F5l8&{a41t^`VQy2?BU|Uhr$Bz3>|5Fo_9w+_{sKf8 zSGp_VA5BeV30H>de@wPjq zIyTA?NI!Psnhd zi|g&n$n<>D%Dw6aq)?!L$n~8EAO4ai5Yj7x=z8Ed7i+^?#3iXAa#z}TG?)Y4XT4jL zo~(&V=O)g&LBzK0`#qp(xA}B7hNMB%FB!t_fzxJDtc8FS09k+CDkG(Bg0r{+# z2fe|+{G8fVe?gBzMnUB69Q?i<=+ONpjPGl%2s%$2wgyD`P@=+*GbsXDDYUw<>`2n& z4q|aUzdZ^dOSE^Q^9*~zh0YV$zA4Q{w8_n6kPs_f!c&#HNPT8aa(?9iw#H%F9P}An zHyV%f{#-bF3*!pIZ6Pi1Hx!(#%omq1%r(Y08u&2T7%H;neTAIMUu7_FdFm=SW@PU_ z?6}m!0<8_SKzd_Ey3Z``A$6sm&82l4f4WX9I(d)zyDYSSH6iAbRPL?h_`1!jcw}S- z{Cy!e%r+5|-`2Ks87~C7gEVJ#NE8E~eJ7)>d4D$dh&w*oy(>vIxWfQI zGw7TFdCIexDKIeR8)78brkooUfUScm8Y91B_muln7e*{G8@lD)Hzh%XFVT5d=su-F1~Ad%W|71 za&8?*(SOee8NqF*a1lURs=U<|89}gWnLp)rRpZxXVUJdALiw#3sQ5W5#?r)B&*K9x z!qAHv5mf*p&}bS-jKM3D_Su*u$i%K(pimi$hVQ2c9qLu%d5| zFN@WCEnYFbvp{=NkpDV1)1)t!=-wK}@Y6g@k%^0{4!^PfmIbvRv4bB4cO{s`IIyGL zQeV+w47*DF1I3#K-LU7EJXD`nrDfmr#&sSsbF95E>j27|xI+%_I8IN_!1VHN!$Bwt ze}qI{03R_?>D3d~)t=A&=`q7cBD>I;jr8trtF0g`xR=FeR*s?Hi>WUuSJUTX-fuE8 zkK+7wM87y+Tw+H1j@!QJ<2cnb`u3M96&kJrGX6`!ITybj$ko9Zy(JV?8}a^aCi}EQ z{$jC#{HTt-5gx2OYrXgyA+HqrSmD4LuOtSuIp~C*9ObnPu>^Bfv0wbh0y8ep|9b04 zI{f|hZVB`3_&anos!8PGc?0sO73;B5g5heR&VKf@Kym~&5n z>|#Z%<^)YXjs7XDAZr@L)fEdqxy#7nq5v~PD-{a@+OX->(a)D*8a_HK?Qr z{;-$!y)xCX03gN9a#VLIaFt5Gh_o#K5B4A{c-0%`gT_eb_HzICEY*5ae^pxWEyZ*) zVGojZ6e;QA?4naN&Ybr|?~F;36)XAWU#UXP1U;uAA{3&le#9cFje3PYrV6Q1aNDlUGa8E-<) z(kaFjtQ+z}$A~7qNp-EX!lo(w|VG%c91m?QvVQYgkJOn3lCAKXvDft7N?2+knG)fk6W=Ak^yEeI)y&> zG>4*JvL$O65_I)CwZ?Ey(FlA7HK~s#Q(>`9ME`2Bd40MW89 zds$BNO8}I<@b|x=98cD1L-^5QdmOO&{U_=qPfTv}eH(lL18z(#9>nKrOpf>Cx|_Zk zg(?lm(BGm^+mXX|VmeuM5OwoD0g9>h3+GUpXdz2?QE(Rw61DnyB)vVum)j|5P|m5) zn7DX9NQ14z&m3@7!~AB}xO&qbFvdv*xD#03h<0#qvCa3F53hUV_a4tZl*|SwuE=QH z$QNLkBg+W`3ApDsO-hH?(-B?)(YaVqE~l{6|Psl;!dJ+&t$L8Bw(I2LTtzNboR+3lj8F>oZcQgmpp}rQ0oG7{?VhE;rFfq~N-)o2?QSoxO?n#Q^9O z@KV<`C!>=(7VhuQCg$e`DewEV6<#3ilqB-w>P8Jt4UH9V9~F08)#=qnx; zWxPd-4FQgXQe1)Ws=r8SH{naf<-;2O7R*9NNVz8^6G86Z+C#8~cz7z}*>QS@P!3P$BcdVw!RjzNS zFYGpXGWiWGZNn%vWCyXHV%k=rMAUESO3WUv6wk4UC(TxvSYgD=cB zg_?-4iR>WwmW{QaNU&rgLR~wCi~ zn5HZbym?b}d_}TlMDwFB0C4WK&VxQo3_~@9t%`MTrW;Ghzsln;yH*_Du>#~obbEY| zcj*IvH4Wz9C|s$1y#5IMJBT)aK){K)XGGjfV>j3kkh?SC%z-$vk_VeDpSR3e9mYj7 zo(Hj3k8PcHsMVCv$B5$RgsA0gFL#4rY{L5pJwh9D=jML96Fj|#d7}Kr-%?n#iroOe_!EJjY(&ONt$7xRq4xcuN^@@Qb5@qw|2DE)nR&bkJ=ZV z*uM7d=r;;CLC#Bytg6c?__$J>7_DS8;(S>Fu$Uu5QTw9d&srgWGVsa6te;ce3Cw`# zjrV z^ZByWM5>$+Hq$LJwfP<^kO#Xci0c>jnFdIh<`V>Jp!}mR1!EDM1ltXWh~$vjgXhh_h*cPr!!zGK%U1{U8EKNYa4JuxtK6 z#gdwRi}{ZmXHGmqvC2>}yANkg3VBr#-X7qKrgXN=6@YT$=FfIu&?r1@CxN7%;%vBT z%2Hj&5OwRnwyA`Jd!6s}F}047O%_wNa#LZz4jc|iaH>@6kpf803;Xz~4g>g~Wht4P z;X#az3(qEc!~xAB*NwRnq5~QZt>KoG=DQ=ODiNLiv7Pci`HrEJQY`aGY!Dl>r9xB1 z8i-O_;zL+%cdYw8QWa^_{rw5DGo{tt%!==6P70%1GQA_Xcq-7{i6qA?9C&FI=cuqbdNG-~*6^RHf#V%wW*jnWIbT>Z70sb(777*7ZlF(cbQ0k4`{!l97n`4H zTPuUTpkf}Gh;BBdSUg=7K^P@06<5)75Q7U$(1X=lDn(Fkg1jC31Af%MyDQ(YfxQ;%)+7ET<4YRL6|6$rBdje zVbB4D+Cwaaf!!ral~-Z_1#BSR*yoDj%~S;RLUezy7pPGmaZyj_M-WYlB5n$l({w{@Qt6M~>vj+}@^v>GF%Hn*Xdhko%!*YocBJ2idvgfA3*pg_Owx6SdYYo=L9*#Zs_HDQf zd3@Cxd=V8GGWbkiRq(SkVvF&QBSZf5<`S9qArA@SB!nLwZhq~rYhU={r2B2t3C2Mm ztVt~rl=;Hm91BwXuCMuso{wf*w~y(=>DsBIDEu7f4urxs&K8w!tlvJ%X1%6Yo=&ek zu!%;Pe}*vrw)U8!siIiFZ|Q}gW}Q=%gw<@Iz{lmolb&0-Hg0NZa!#JeauMb|FO6T{ zhx0p@|I2xT{7(Nbi6=!Pui9k`f?O2kpZeRYwI87LcOdzejypCusunOe7~wg=;fSfd$Sc9AjYP|gB+5Shr>%Zz33gd)4_ zErinmOucRJhML)FN4TF?jl-LFT~rRiHXiTmmvyX3reuBT|K?Kn8WN zHB4?-0JT@lj^PouryGhR;+MpZoEAff2T0!23K z2jb^8;V6t3O7m(eUfYz&5^lpP?;!4&>#&TVl*xNOF37P@Rb)o=v(r_iqrtqeRfEGF zj+W7j0^i>GvIgik2$pM+k_Tv-Xxe6ol?-H|JZ&ul&J$+8pB0rG^`u4Idai?*?rdV` zU3<`*Z0~k_j@I}Uk`*#q{pXC@^LP`-o@BlWDHVb}^tZi0Bs*7o5A7#z@kTaPPp3Ks zy{9Y`xkz>0bg|?LrbI8XtKT#<$E~A1WNQ6D*@N_@bL83O+r<8wV1R4QO?h{h;o}$Z z*|d*g#f_`0jWQR=M0s$l+#`mf`J2%yo(EK(QD3!*aLRWuKpP^$`8GoLXE&cFkMv4* z%SO%ASQVZ?S)7&+KGC%Z7yFkaem}rM(+DEepLEwd8*L~z;iQg3T3H#bGCLRJpRXCo z$QH18KCkvo5B4&B`Pv~a1xW)(LZY5~xahLK%g*B2yixKj3$&X1a7F@qzVOky#wSyQ z9{~>F(d(KNN5}G$J;2}oOg-lcPPD?bR${$ZioT>Hch$!ECVYx$RyOOe+%-8XC?@PN zW4e5mS13o@yS`JF;tNx~fb3V}%JCa`bh!~=#A|i#wv=qFz+FziZs2CZIqkd#w&`nU zi{wTOBt&lV23xtgL6zp01~VhXtB%GalhA}IqoQsG=EpS>ZkmH^q4HsEuIz4WAHY!o z!0cQqX*c2pKCDxtBC%tDo4bp5CZF+dKQ+D*w>$|$TF=KXzwXbgaP&?Ao!^}|L?5&( z?D`j1Hus}TB#?J%a*)Y@8zQgn$6OL+19u)1t|`uFF}e9aRd-Sgt#K zmK()06zf=N=BKF~r=hFBjpr}FfMCGqBq;A{Ag1TZGFR6y8PxN)%GdL|-y@N5-FS_T z3J>YWoy+O{<_FMt^%Vha-Nz86!MlHC{Y~*Va@ublQUl^g&-V2(ZKYlH%9Vd_3Oy;1N7y(GXQCG`Ha_v;Hj5(cHIs)DVp?hXgN0!$Z&W>^OY9g4tsv3&#P-u z8nXR=T4y&}ga3%Z%S6N7&E%vsXdcAq!tLW8mRv!vjM!*^0($EMTgB%b>auYdO~kD&Q`>`mJchM0>YLt4e4-`|;f~-!4#Qq2py{)tQc6sK?Fj-1 z&6I4Z04n4}4<2RbJPJkrcAp#7yTr`!TuLA{FAEiubX*8_kZ2TaC89g~Ad9R~a#8VL zhL6Q+@I7PZHnpIA3n%MgRG&XO1`;YiaZ+F9QO~QiO>Tu363uwGn%ei*myR zKuH#5VnGI{|4xU|RxYel3at#1w>3fTRHnr^6tX4SfakII{fhxCybB?^plMvGibdG) zT@n%|JIK+vmX7%keU6P_`4n&~(Dhx2qQwd(BGbqaHW+IS8Y%fX#p*@jPK)vo%|!I! zUOuYYpSnf43QJgZa^z?{H1kLM#QbBQSWKdUOvIZ)GP6vIuam2UAgFN|b3hF7D%nMt zhC&faYaScZjF;1IHcJ{%9G6Knd?gC&>cUExtpmfLk2r_C1vU7z@BGbdHiGK31uAc3 zNOgxYye|=P0ITcbO5y-jkv*~R2bb}R0hf+09T)Qf8f*7AP=cFOxQRSDjF_4OQ)*$WsTdomHXVs8!_<>+1C?Y6mjE+!%%rhG zBYF&H+VK>OnHV|gu0;8|ZZ%-_JMj=|qIPam|OGjcsd) zd!g0H*SdMRzdpGVq_EL*>*4!p zvw#m834PsK6w>0fkqmiknTT|ocy$m;3*UdG0~JV?OcXXRGsQIP`B&R8TUYios1JXo zcx+Rj*WCZ3)$v01S~7j2_E=;|+{|9oBelBr-<_}*SvGIgj62NF1Z&Xk$*xgxTg%tA zSh#_uPi)4FY@$(@1f+xgnmeDOliUWM(Nsf9P#to&5CfW3X^Y(WRwo5hHGc~mi(YQ& znGW`8iApj^za_$-J@1Dz*-W~ z&rO|D6W$b>AohN16LU%8J*|0MOmWQh|D6HE10TKtF3KC~ce}yMRZW(KvZmgzPn^bk zoiQ)yj5phe(lU3Dt)&zi zNK@S&Ru>IFg{MyLU|0|d^{@f`DnK<$snl)XoVU78Hub_X4A~)XE=6{=>nZqyJjwW6 z3Z12@>HuhR1Ey#4ux80Mih;qLg>;Pk?#H_7W15H7_0NEp$;&1g+X`HYrSGnY=%*he z9bNA&juxhXPZ_TWYb%~k^D>7 zAblji&;q!01`nAlxkDcST2BeR;p*aJ=@ut*=JrS52CpV zaZ$tkrv=A^FQtHf?(!Ion&AMO9rouG>U4bd-`MT=c-89JK44Q#G-NPOnR5|Y{ipCo z%L;jj9mJm1+d_no=_@Yw?UOfB(OuM9zZ=H+4bT%Y4FLJ42IX84S+rndi_6;lsPRguSRz4Gu}Kf$)x-G9h`G1Z zs45gc`z4WKStlk>lDm3f)zurEkoA+go*iwBikxl9iKH-Xi_uP^&YfkA zb)2U)=Xn?oL{0Rd6D~guM}k$AITPvB$sfsZk!8dg zJa(43mTT8C+QV@K_Fs|itX--!3}%9%QO2h$cX|6&h}vYrohQ*zi4SpEsd9SO4Fz@4 z&;<)D&I*Nn1-mO^q@+yUGaClK0zT7S;|DHKx?m*f$ygBimxbg|4}SKOMMacY14Wfx z9h6)jZlBH!msrg7h_I|a8}x?*gumJ&?!rlKKBA~{)yWb}o8$`#c` zorL)88J$2qu9N*``jW`;9Lu;v8+5zNglJK9T$0zf%z31hAe1cMsCM)eG6mmYS8LQw z9H+@=u3Hoaocj-GzG8{!*!t*TvvF7={2}Sd;9nq&fpVsErwN~}T+>sKiWEOtHg65d z)^?=jb$(q7>L`+FXZbL@b7{R`*$A$vk3v_p zSUpib>bYF3a}NblZLOPS4l>5jo{FBxtVVN!y`|r)vEStGp7tTfSVb>vEGJ$^EIDDm z=O02Ssf{JRH7809mBuegL$qsea(KFBYVJpgSNC^FA_V}q`i?&Ns=0N*B8yqKWkd?He zmO2ZU<=+DJP74)s_)U^bejY|}YYp;v+D#mXX_hgzcvNtBIqrFeX^v?jLgQy5RC0*!xn5+`TVA*4j|I5kZevvyO21Fdnaw+nTDK4474MP|0yyrh)|*jX7K z$Pw9_rJ6`xM6PcK<~#^t(U*xR$0-|iKi$}n)+4j1g=Ae{UHq%JbS`M4w|z$?HjM!Z zeZ2O3LSEI9i44$$@JsSJp_=Jc%=xm&sMWu>vxKc1A9^PBE2}{=!sx~2^>p%9Qk##L zJB3sm|KWMh^_nz6+Plh%^(A6tOaX?1CCb7x;Cu+~yHB0UZ773Nv%t=qW;mjV!zRh% zN!rI97_hj|&=6wd4N&+Jt7!Q^ebQ3txvhDAt z$JW*<VeRAxr3LfPxfsFb!-D9e*AN;*<2l&ZX+S*Vj|`@r9S9fIQpa;IRDVAqGR z_RmIz9zx_f#qp&Y|EM?&R8Eh?{!sf&wc(Q?9JzKaNs+pJFY`@O625m7oQgAJBF1Sj zy?RMe(e{sVmxVve%nuAi2zBvno)UIuQB=z_ zH+&)Wh}Dh=D2m$oUi8;a2zOn~&2wT4)l;!}v{}uVVBu2ZCj0gc{WK}6PNgMAQJJ1WON2nZEEa~G0=X96!y3V(=TUaJ1E?%my+1N+fuX*onS1+@G zq!=`fVh0^z{N@#{2$!oBOQ!IF(I_X%M7k2`Rp)jz3ssDHD;CEQpV~o zt!YjM$em!3zibyo*)}^J@rH{=SC#|b4LlA;4g^4+MT%y!x@ZK3)UYA%lzBCne|%N= z^akKK<iJwCGPhj%4}3bI-WBgPrM-{Tmf`-lXUQQ|}jPSZW8{M6+J|64HF zh9g*0=AYcv+n0;8Li&T4N4CvZpOL^2f!pMT_XM^#ve zs+{Ct_Sta;1$-lu#&!2_-WisA@(ACnsUEzli0=|A4C$_0#1K-gmI$hP{OFSUFgci)h7#2KzMNLD})8plGe zD_n2oZ-GG%Je+}$6V6977AcOE2BUN`fC9=qB8hX4g>-3!@eF+xn2E}Kqk;znYPiWH zzw5;!Dj9qb+fss49J{aZ*P~PhX##YT3FVdX{ueUf4B#ezeO$GmF=;cbPO1gB^=IEVc%uYXxDq zKz&|LF}KKF5h~Sca~lJ;wuUAbXJ^wcC)%*;kKO%UMot{vZk3{>djghax)}w(`=}fG zeo(#I&<6z;rzWH>AL{1?;(XTQ8!&g7W@)iIdp5n?7w-AHweq#c;BJS73!V(wZERmq z*45Y2|BS9~`~+bdPwA`=d8hfF-qBg=1qlAclp(WNIk-#$a5Zo@fuaf2U(!&opSih` znfL_B%3?I=6Hjk-3IzDYP&`()x2nwpb9veRAmEPF#nkYN zmLMV&T{EmYu-PE2GFg!;;?&+m$Ns?-?6T5en7iIPkxMcc`8dDjK21>@jji`1b!@!u z+i9fidjH^&HxC8(DDGqkSY3P3JD_p-zU&@uMjGzSFSvxm9%dd(&1gB+DZEO2wg6MY zy|P7ruqS|_NTk_Gw)OXEdM~dwtr)l_JjR?O)%ypx2nu+k%i3C;%tpb~32s6|t3Jmt z9XW9A#f6W2D=@A$n+c~1WwKH)s)Oj!@`>prLTim}sGWb4I`B6Q=AANw1(A9O6Fl^5 zEC7P0Cn!pQEK>(ng-6!8Ba5P=)xj*>D91zpno%Jym8I6=a42e^M?l^$yxdL{pi-(A zq!*>au_m9`M`i?>ytVX6d^-B4VfQNw@2RrQvU<8LM9O`zK_)TB)*a4rggdX}XHeWw z6io?_*}kNUhUKUfZh4Nj1KGf3wy(ZcEO%4)$<6Q!N&Df#7f2aoTR zScmNzgur24XKwyv!!PUM%7x-o(kKhQc{&m;=cUp2zB41oDV4uFYw9InTfL1tknid$ z3WYMNScN!{nm2t_*i|@NEC8JMp#I!?To}1lwM1& z7j�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 ~Js7-*xjgY$ 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 + +
+
MKAnnotationView+WebCache.h
+ +
+
Added -[MKAnnotationView sd_setImageWithURL:placeholderImage:options:context:]
+
Added -[MKAnnotationView sd_setImageWithURL:placeholderImage:options:progress:completed:]
+
Added -[MKAnnotationView sd_setImageWithURL:placeholderImage:options:context:progress:completed:]
+
+ +
+ +
+
SDAnimatedImage.h
+ +
+
Added SDAnimatedImage
+
Added -[SDAnimatedImage initWithAnimatedCoder:scale:]
+
Added -[SDAnimatedImage preloadAllFrames]
+
Added -[SDAnimatedImage unloadAllFrames]
+
Added -[SDAnimatedImage isAllFramesLoaded]
+
Added SDAnimatedImage
+
Added +[SDAnimatedImage imageNamed:]
+
Added +[SDAnimatedImage imageNamed:inBundle:compatibleWithTraitCollection:]
+
Added +[SDAnimatedImage imageWithContentsOfFile:]
+
Added +[SDAnimatedImage imageWithData:]
+
Added +[SDAnimatedImage imageWithData:scale:]
+
Added -[SDAnimatedImage initWithContentsOfFile:]
+
Added -[SDAnimatedImage initWithData:]
+
Added -[SDAnimatedImage initWithData:scale:]
+
Added -[SDAnimatedImage initWithAnimatedCoder:scale:]
+
Added SDAnimatedImage.animatedImageFormat
+
Added SDAnimatedImage.animatedImageData
+
Added SDAnimatedImage.scale
+
Added -[SDAnimatedImage preloadAllFrames]
+
Added -[SDAnimatedImage unloadAllFrames]
+
Added SDAnimatedImage.allFramesLoaded
+
+ +
+ +
+
SDAnimatedImageView.h
+ +
+
Added SDAnimatedImageView
+
Added SDAnimatedImageView.currentFrame
+
Added SDAnimatedImageView.currentFrameIndex
+
Added SDAnimatedImageView.currentLoopCount
+
Added SDAnimatedImageView.shouldCustomLoopCount
+
Added SDAnimatedImageView.animationRepeatCount
+
Added SDAnimatedImageView.maxBufferSize
+
Added SDAnimatedImageView.shouldIncrementalLoad
+
Added SDAnimatedImageView.runLoopMode
+
+ +
+ +
+
SDAnimatedImageView+WebCache.h
+ +
+
Added -[SDAnimatedImageView sd_setImageWithURL:]
+
Added -[SDAnimatedImageView sd_setImageWithURL:placeholderImage:]
+
Added -[SDAnimatedImageView sd_setImageWithURL:placeholderImage:options:]
+
Added -[SDAnimatedImageView sd_setImageWithURL:placeholderImage:options:context:]
+
Added -[SDAnimatedImageView sd_setImageWithURL:completed:]
+
Added -[SDAnimatedImageView sd_setImageWithURL:placeholderImage:completed:]
+
Added -[SDAnimatedImageView sd_setImageWithURL:placeholderImage:options:completed:]
+
Added -[SDAnimatedImageView sd_setImageWithURL:placeholderImage:options:progress:completed:]
+
Added -[SDAnimatedImageView sd_setImageWithURL:placeholderImage:options:context:progress:completed:]
+
+ +
+ +
+
SDDiskCache.h
+ +
+
Added SDDiskCache
+
Added -[SDDiskCache initWithCachePath:config:]
+
Added -[SDDiskCache containsDataForKey:]
+
Added -[SDDiskCache dataForKey:]
+
Added -[SDDiskCache setData:forKey:]
+
Added -[SDDiskCache removeDataForKey:]
+
Added -[SDDiskCache removeAllData]
+
Added -[SDDiskCache removeExpiredData]
+
Added -[SDDiskCache cachePathForKey:]
+
Added -[SDDiskCache totalCount]
+
Added -[SDDiskCache totalSize]
+
Added SDDiskCache
+
Added SDDiskCache.config
+
+ +
+ +
+
SDImageAPNGCoder.h
+ +
+
Added SDImageAPNGCoder
+
Added SDImageAPNGCoder.sharedCoder
+
+ +
+ +
+
SDImageCache.h
+ +
+
Removed SDImageCacheQueryDataWhenInMemory
+
Removed SDImageCacheQueryDiskSync
+
Removed SDCacheQueryCompletedBlock
+
Removed SDWebImageCheckCacheCompletionBlock
+
Removed SDWebImageCalculateSizeBlock
+
Removed SDImageCache.maxMemoryCost
+
Removed SDImageCache.maxMemoryCountLimit
+
Removed -[SDImageCache makeDiskCachePath:]
+
Removed -[SDImageCache addReadOnlyCachePath:]
+
Removed -[SDImageCache cachePathForKey:inPath:]
+
Removed -[SDImageCache defaultCachePathForKey:]
+
+ + +
+
Added SDImageCacheQueryMemoryData
+
Added SDImageCacheQueryMemoryDataSync
+
Added SDImageCacheQueryDiskDataSync
+
Added SDImageCacheAvoidDecodeImage
+
Added SDImageCacheDecodeFirstFrameOnly
+
Added SDImageCachePreloadAllFrames
+
Added SDImageCache.diskCachePath
+
Added SDImageCache.additionalCachePathBlock
+
Added -[SDImageCache initWithNamespace:diskCacheDirectory:config:]
+
Added -[SDImageCache cachePathForKey:]
+
Added -[SDImageCache storeImageToMemory:forKey:]
+
Added -[SDImageCache queryCacheOperationForKey:options:context:done:]
+
Added -[SDImageCache removeImageFromMemoryForKey:]
+
Added -[SDImageCache removeImageFromDiskForKey:]
+
+ + +
+
Modified SDImageCache
+ + + + +
Protocols
Fromnone
ToSDImageCache
+
+
Modified SDImageCache.config
+ + + + +
Declaration
From@property (nonatomic, readonly, nonnull) SDImageCacheConfig *config
To@property (nonatomic, readonly, copy, nonnull) SDImageCacheConfig *config
+
+
Modified +[SDImageCache sharedImageCache]
+ + + + +
Declaration
From+ (nonnull instancetype)sharedImageCache
To@property (class, nonatomic, readonly, nonnull) SDImageCache *sharedImageCache
+
+
Modified -[SDImageCache diskImageExistsWithKey:completion:]
+ + + + +
Declaration
From- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock
To- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDImageCacheCheckCompletionBlock)completionBlock
+
+
Modified -[SDImageCache queryCacheOperationForKey:done:]
+ + + + +
Declaration
From- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock
To- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDImageCacheQueryCompletionBlock)doneBlock
+
+
Modified -[SDImageCache queryCacheOperationForKey:options:done:]
+ + + + +
Declaration
From- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock
To- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDImageCacheQueryCompletionBlock)doneBlock
+
+
Modified -[SDImageCache calculateSizeWithCompletionBlock:]
+ + + + +
Declaration
From- (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock
To- (void)calculateSizeWithCompletionBlock:(nullable SDImageCacheCalculateSizeBlock)completionBlock
+
+
+ +
+ +
+
SDImageCacheConfig.h
+ +
+
Removed SDImageCacheConfig.shouldDecompressImages
+
+ + +
+
Added SDImageCacheConfig.defaultCacheConfig
+
Added SDImageCacheConfig.shouldRemoveExpiredDataWhenEnterBackground
+
Added SDImageCacheConfig.maxMemoryCost
+
Added SDImageCacheConfig.maxMemoryCount
+
Added SDImageCacheConfig.namespacePrefix
+
Added SDImageCacheConfig.fileManager
+
Added SDImageCacheConfig.memoryCacheClass
+
Added SDImageCacheConfig.diskCacheClass
+
+ + +
+
Modified SDImageCacheConfig
+ + + + +
Protocols
Fromnone
ToNSCopying
+
+
Modified SDImageCacheConfig.maxCacheAge
+ + + + +
Declaration
From@property (nonatomic, assign) NSInteger maxCacheAge
To@property (nonatomic, assign) NSTimeInterval maxCacheAge
+
+
+ +
+ +
+
SDImageCacheDefine.h
+ +
+
Added SDImageCacheTypeAll
+
Added SDImageCacheCheckCompletionBlock
+
Added SDImageCacheCalculateSizeBlock
+
Added SDImageCacheAdditionalCachePathBlock
+
Added SDImageCacheQueryCompletionBlock
+
Added SDImageCacheContainsCompletionBlock
+
Added SDImageCacheDecodeImageData()
+
Added SDImageCache
+
Added -[SDImageCache queryImageForKey:options:context:completion:]
+
Added -[SDImageCache storeImage:imageData:forKey:cacheType:completion:]
+
Added -[SDImageCache removeImageForKey:cacheType:completion:]
+
Added -[SDImageCache containsImageForKey:cacheType:completion:]
+
Added -[SDImageCache clearWithCacheType:completion:]
+
+ +
+ +
+
SDImageCachesManager.h
+ +
+
Added SDImageCachesManagerOperationPolicy
+
Added SDImageCachesManagerOperationPolicySerial
+
Added SDImageCachesManagerOperationPolicyConcurrent
+
Added SDImageCachesManagerOperationPolicyHighestOnly
+
Added SDImageCachesManagerOperationPolicyLowestOnly
+
Added SDImageCachesManager
+
Added SDImageCachesManager.sharedManager
+
Added SDImageCachesManager.queryOperationPolicy
+
Added SDImageCachesManager.storeOperationPolicy
+
Added SDImageCachesManager.removeOperationPolicy
+
Added SDImageCachesManager.containsOperationPolicy
+
Added SDImageCachesManager.clearOperationPolicy
+
Added SDImageCachesManager.caches
+
Added -[SDImageCachesManager addCache:]
+
Added -[SDImageCachesManager removeCache:]
+
+ +
+ +
+
SDImageCoder.h
+ +
+
Added SDImageCoderOption
+
Added SDImageCoderOptions
+
Added SDImageCoderDecodeFirstFrameOnly
+
Added SDImageCoderDecodeScaleFactor
+
Added SDImageCoderEncodeFirstFrameOnly
+
Added SDImageCoderEncodeCompressionQuality
+
Added SDImageCoder
+
Added -[SDImageCoder canDecodeFromData:]
+
Added -[SDImageCoder decodedImageWithData:options:]
+
Added -[SDImageCoder canEncodeToFormat:]
+
Added -[SDImageCoder encodedDataWithImage:format:options:]
+
Added SDProgressiveImageCoder
+
Added -[SDProgressiveImageCoder canIncrementalDecodeFromData:]
+
Added -[SDProgressiveImageCoder initIncrementalWithOptions:]
+
Added -[SDProgressiveImageCoder updateIncrementalData:finished:]
+
Added -[SDProgressiveImageCoder incrementalDecodedImageWithOptions:]
+
Added SDAnimatedImageProvider
+
Added -[SDAnimatedImageProvider animatedImageData]
+
Added -[SDAnimatedImageProvider animatedImageFrameCount]
+
Added -[SDAnimatedImageProvider animatedImageLoopCount]
+
Added -[SDAnimatedImageProvider animatedImageFrameAtIndex:]
+
Added -[SDAnimatedImageProvider animatedImageDurationAtIndex:]
+
Added SDAnimatedImageCoder
+
Added -[SDAnimatedImageCoder initWithAnimatedImageData:options:]
+
+ +
+ +
+
SDImageCoderHelper.h
+ +
+
Added SDImageCoderHelper
+
Added +[SDImageCoderHelper animatedImageWithFrames:]
+
Added +[SDImageCoderHelper framesFromAnimatedImage:]
+
Added +[SDImageCoderHelper colorSpaceGetDeviceRGB]
+
Added +[SDImageCoderHelper CGImageContainsAlpha:]
+
Added +[SDImageCoderHelper CGImageCreateDecoded:]
+
Added +[SDImageCoderHelper CGImageCreateDecoded:orientation:]
+
Added +[SDImageCoderHelper decodedImageWithImage:]
+
Added +[SDImageCoderHelper decodedAndScaledDownImageWithImage:limitBytes:]
+
Added +[SDImageCoderHelper imageOrientationFromEXIFOrientation:]
+
Added +[SDImageCoderHelper exifOrientationFromImageOrientation:]
+
+ +
+ +
+
SDImageCodersManager.h
+ +
+
Added SDImageCodersManager
+
Added SDImageCodersManager.sharedManager
+
Added SDImageCodersManager.coders
+
Added -[SDImageCodersManager addCoder:]
+
Added -[SDImageCodersManager removeCoder:]
+
+ +
+ +
+
SDImageFrame.h
+ +
+
Added SDImageFrame
+
Added SDImageFrame.image
+
Added SDImageFrame.duration
+
Added +[SDImageFrame frameWithImage:duration:]
+
+ +
+ +
+
SDImageGIFCoder.h
+ +
+
Added SDImageGIFCoder
+
Added SDImageGIFCoder.sharedCoder
+
+ +
+ +
+
SDImageIOCoder.h
+ +
+
Added SDImageIOCoder
+
Added SDImageIOCoder.sharedCoder
+
+ +
+ +
+
SDImageLoader.h
+ +
+
Added SDImageLoaderProgressBlock
+
Added SDImageLoaderCompletedBlock
+
Added SDWebImageContextLoaderCachedImage
+
Added SDImageLoaderDecodeImageData()
+
Added SDImageLoaderDecodeProgressiveImageData()
+
Added SDImageLoader
+
Added -[SDImageLoader canLoadWithURL:]
+
Added -[SDImageLoader loadImageWithURL:options:context:progress:completed:]
+
+ +
+ +
+
SDImageLoadersManager.h
+ +
+
Added SDImageLoadersManager
+
Added SDImageLoadersManager.sharedManager
+
Added SDImageLoadersManager.loaders
+
Added -[SDImageLoadersManager addLoader:]
+
Added -[SDImageLoadersManager removeLoader:]
+
+ +
+ +
+
SDImageTransformer.h
+ +
+
Added SDTransformedKeyForKey()
+
Added SDImageTransformer
+
Added -[SDImageTransformer transformerKey]
+
Added -[SDImageTransformer transformedImageWithImage:forKey:]
+
Added SDImagePipelineTransformer
+
Added SDImagePipelineTransformer.transformers
+
Added +[SDImagePipelineTransformer transformerWithTransformers:]
+
Added SDImageRoundCornerTransformer
+
Added SDImageRoundCornerTransformer.cornerRadius
+
Added SDImageRoundCornerTransformer.corners
+
Added SDImageRoundCornerTransformer.borderWidth
+
Added SDImageRoundCornerTransformer.borderColor
+
Added +[SDImageRoundCornerTransformer transformerWithRadius:corners:borderWidth:borderColor:]
+
Added SDImageResizingTransformer
+
Added SDImageResizingTransformer.size
+
Added SDImageResizingTransformer.scaleMode
+
Added +[SDImageResizingTransformer transformerWithSize:scaleMode:]
+
Added SDImageCroppingTransformer
+
Added SDImageCroppingTransformer.rect
+
Added +[SDImageCroppingTransformer transformerWithRect:]
+
Added SDImageFlippingTransformer
+
Added SDImageFlippingTransformer.horizontal
+
Added SDImageFlippingTransformer.vertical
+
Added +[SDImageFlippingTransformer transformerWithHorizontal:vertical:]
+
Added SDImageRotationTransformer
+
Added SDImageRotationTransformer.angle
+
Added SDImageRotationTransformer.fitSize
+
Added +[SDImageRotationTransformer transformerWithAngle:fitSize:]
+
Added SDImageTintTransformer
+
Added SDImageTintTransformer.tintColor
+
Added +[SDImageTintTransformer transformerWithColor:]
+
Added SDImageBlurTransformer
+
Added SDImageBlurTransformer.blurRadius
+
Added +[SDImageBlurTransformer transformerWithRadius:]
+
Added SDImageFilterTransformer
+
Added SDImageFilterTransformer.filter
+
Added +[SDImageFilterTransformer transformerWithFilter:]
+
+ +
+ +
+
SDMemoryCache.h
+ +
+
Added SDMemoryCacheCostForImage()
+
Added SDMemoryCache
+
Added -[SDMemoryCache initWithConfig:]
+
Added -[SDMemoryCache objectForKey:]
+
Added -[SDMemoryCache setObject:forKey:]
+
Added -[SDMemoryCache setObject:forKey:cost:]
+
Added -[SDMemoryCache removeObjectForKey:]
+
Added -[SDMemoryCache removeAllObjects]
+
Added SDMemoryCache
+
Added SDMemoryCache.config
+
+ +
+ +
+
SDWebImageCacheKeyFilter.h
+ +
+
Added SDWebImageCacheKeyFilter
+
Added -[SDWebImageCacheKeyFilter cacheKeyForURL:]
+
Added SDWebImageCacheKeyFilter
+
Added -[SDWebImageCacheKeyFilter initWithBlock:]
+
Added +[SDWebImageCacheKeyFilter cacheKeyFilterWithBlock:]
+
+ + +
+
Modified SDWebImageCacheKeyFilterBlock
+ + + + +
Declaration
Fromtypedef NSString * _Nullable (^SDWebImageCacheKeyFilterBlock)(NSURL * _Nullable url)
Totypedef NSString * _Nullable (^SDWebImageCacheKeyFilterBlock)(NSURL * _Nonnull url)
+
+
+ +
+ +
+
SDWebImageCacheSerializer.h
+ +
+
Added SDWebImageCacheSerializer
+
Added -[SDWebImageCacheSerializer cacheDataWithImage:originalData:imageURL:]
+
Added SDWebImageCacheSerializer
+
Added -[SDWebImageCacheSerializer initWithBlock:]
+
Added +[SDWebImageCacheSerializer cacheSerializerWithBlock:]
+
+ +
+ +
+
SDWebImageCoder.h
+ +
+
Removed SDWebImageCoderScaleDownLargeImagesKey
+
Removed SDCGColorSpaceGetDeviceRGB()
+
Removed SDCGImageRefContainsAlpha()
+
Removed SDWebImageCoder
+
Removed -[SDWebImageCoder canDecodeFromData:]
+
Removed -[SDWebImageCoder decodedImageWithData:]
+
Removed -[SDWebImageCoder decompressedImageWithImage:data:options:]
+
Removed -[SDWebImageCoder canEncodeToFormat:]
+
Removed -[SDWebImageCoder encodedDataWithImage:format:]
+
Removed SDWebImageProgressiveCoder
+
Removed -[SDWebImageProgressiveCoder canIncrementallyDecodeFromData:]
+
Removed -[SDWebImageProgressiveCoder incrementallyDecodedImageWithData:finished:]
+
+ +
+ +
+
SDWebImageCoderHelper.h
+ +
+
Removed SDWebImageCoderHelper
+
Removed +[SDWebImageCoderHelper animatedImageWithFrames:]
+
Removed +[SDWebImageCoderHelper framesFromAnimatedImage:]
+
Removed +[SDWebImageCoderHelper imageOrientationFromEXIFOrientation:]
+
Removed +[SDWebImageCoderHelper exifOrientationFromImageOrientation:]
+
+ +
+ +
+
SDWebImageCodersManager.h
+ +
+
Removed SDWebImageCodersManager
+
Removed +[SDWebImageCodersManager sharedInstance]
+
Removed SDWebImageCodersManager.coders
+
Removed -[SDWebImageCodersManager addCoder:]
+
Removed -[SDWebImageCodersManager removeCoder:]
+
+ +
+ +
+
SDWebImageCompat.h
+ +
+
Removed #def dispatch_queue_async_safe
+
+ +
+ +
+
SDWebImageDefine.h
+ +
+
Added SDWebImageContextOption
+
Added SDWebImageContext
+
Added SDWebImageMutableContext
+
Added SDImageScaleFactorForKey()
+
Added SDScaledImageForScaleFactor()
+
Added SDWebImageProgressiveLoad
+
Added SDWebImageQueryMemoryData
+
Added SDWebImageQueryMemoryDataSync
+
Added SDWebImageQueryDiskDataSync
+
Added SDWebImageFromLoaderOnly
+
Added SDWebImageAvoidDecodeImage
+
Added SDWebImageDecodeFirstFrameOnly
+
Added SDWebImagePreloadAllFrames
+
Added SDWebImageContextSetImageOperationKey
+
Added SDWebImageContextSetImageGroup
+
Added SDWebImageContextCustomManager
+
Added SDWebImageContextImageTransformer
+
Added SDWebImageContextImageScaleFactor
+
Added SDWebImageContextStoreCacheType
+
Added SDWebImageContextAnimatedImageClass
+
Added SDWebImageContextDownloadRequestModifier
+
Added SDWebImageContextCacheKeyFilter
+
Added SDWebImageContextCacheSerializer
+
+ + +
+
Modified SDScaledImageForKey()
+ + + + +
Declaration
FromUIImage *SDScaledImageForKey(NSString *key, UIImage *image)
ToUIImage * _Nullable SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image)
+
+
+ +
+ +
+
SDWebImageDownloader.h
+ +
+
Removed SDWebImageDownloaderProgressiveDownload
+
Removed SDHTTPHeadersDictionary
+
Removed SDHTTPHeadersMutableDictionary
+
Removed SDWebImageDownloaderHeadersFilterBlock
+
Removed SDWebImageDownloadToken.downloadOperationCancelToken
+
Removed SDWebImageDownloader.shouldDecompressImages
+
Removed SDWebImageDownloader.maxConcurrentDownloads
+
Removed SDWebImageDownloader.downloadTimeout
+
Removed SDWebImageDownloader.executionOrder
+
Removed SDWebImageDownloader.urlCredential
+
Removed SDWebImageDownloader.username
+
Removed SDWebImageDownloader.password
+
Removed SDWebImageDownloader.headersFilter
+
Removed -[SDWebImageDownloader initWithSessionConfiguration:]
+
Removed -[SDWebImageDownloader setOperationClass:]
+
Removed -[SDWebImageDownloader cancel:]
+
Removed -[SDWebImageDownloader createNewSessionWithConfiguration:]
+
+ + +
+
Added SDWebImageDownloaderProgressiveLoad
+
Added SDWebImageDownloaderAvoidDecodeImage
+
Added SDWebImageDownloaderDecodeFirstFrameOnly
+
Added SDWebImageDownloaderPreloadAllFrames
+
Added -[SDWebImageDownloadToken cancel]
+
Added SDWebImageDownloadToken.request
+
Added SDWebImageDownloadToken.response
+
Added SDWebImageDownloader.config
+
Added SDWebImageDownloader.requestModifier
+
Added -[SDWebImageDownloader initWithConfig:]
+
Added -[SDWebImageDownloader downloadImageWithURL:options:context:progress:completed:]
+
+ + +
+
Modified SDWebImageDownloaderProgressBlock
+ + + + +
Declaration
Fromtypedef void (^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL)
Totypedef SDWebImageDownloaderProgressBlock SDWebImageDownloaderProgressBlock
+
+
Modified SDWebImageDownloaderCompletedBlock
+ + + + +
Declaration
Fromtypedef void (^SDWebImageDownloaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished)
Totypedef SDWebImageDownloaderCompletedBlock SDWebImageDownloaderCompletedBlock
+
+
Modified SDWebImageDownloadToken.url
+ + + + +
Declaration
From@property (nonatomic, strong, nullable) NSURL *url
To@property (nonatomic, readonly, strong, nullable) NSURL *url
+
+
Modified SDWebImageDownloader
+ + + + +
Protocols
Fromnone
ToSDImageLoader
+
+
Modified -[SDWebImageDownloader setSuspended:]
+ + + + +
Declaration
From- (void)setSuspended:(BOOL)suspended
To@property (nonatomic, assign, getter=isSuspended) BOOL suspended
+
+
Modified SDWebImageDownloader.currentDownloadCount
+ + + + +
Declaration
From@property (nonatomic, readonly) NSUInteger currentDownloadCount
To@property (nonatomic, readonly, assign) NSUInteger currentDownloadCount
+
+
Modified +[SDWebImageDownloader sharedDownloader]
+ + + + +
Declaration
From+ (nonnull instancetype)sharedDownloader
To@property (class, nonatomic, readonly, nonnull) SDWebImageDownloader *sharedDownloader
+
+
+ +
+ +
+
SDWebImageDownloaderConfig.h
+ +
+
Added SDWebImageDownloaderConfig
+
Added SDWebImageDownloaderConfig.defaultDownloaderConfig
+
Added SDWebImageDownloaderConfig.maxConcurrentDownloads
+
Added SDWebImageDownloaderConfig.downloadTimeout
+
Added SDWebImageDownloaderConfig.sessionConfiguration
+
Added SDWebImageDownloaderConfig.operationClass
+
Added SDWebImageDownloaderConfig.executionOrder
+
Added SDWebImageDownloaderConfig.urlCredential
+
Added SDWebImageDownloaderConfig.username
+
Added SDWebImageDownloaderConfig.password
+
+ +
+ +
+
SDWebImageDownloaderOperation.h
+ +
+
Removed SDWebImageDownloaderOperationInterface
+
Removed -[SDWebImageDownloaderOperationInterface initWithRequest:inSession:options:]
+
Removed -[SDWebImageDownloaderOperationInterface addHandlersForProgress:completed:]
+
Removed -[SDWebImageDownloaderOperationInterface shouldDecompressImages]
+
Removed -[SDWebImageDownloaderOperationInterface setShouldDecompressImages:]
+
Removed -[SDWebImageDownloaderOperationInterface credential]
+
Removed -[SDWebImageDownloaderOperationInterface setCredential:]
+
Removed -[SDWebImageDownloaderOperationInterface cancel:]
+
Removed SDWebImageDownloaderOperation.shouldDecompressImages
+
Removed SDWebImageDownloaderOperation.shouldUseCredentialStorage
+
Removed SDWebImageDownloaderOperation.expectedSize
+
+ + +
+
Added SDWebImageDownloaderOperation
+
Added -[SDWebImageDownloaderOperation initWithRequest:inSession:options:]
+
Added -[SDWebImageDownloaderOperation initWithRequest:inSession:options:context:]
+
Added -[SDWebImageDownloaderOperation addHandlersForProgress:completed:]
+
Added -[SDWebImageDownloaderOperation credential]
+
Added -[SDWebImageDownloaderOperation setCredential:]
+
Added -[SDWebImageDownloaderOperation cancel:]
+
Added -[SDWebImageDownloaderOperation request]
+
Added -[SDWebImageDownloaderOperation response]
+
Added -[SDWebImageDownloaderOperation dataTask]
+
Added SDWebImageDownloaderOperation.context
+
Added -[SDWebImageDownloaderOperation initWithRequest:inSession:options:context:]
+
+ + +
+
Modified SDWebImageDownloaderOperation
+ + + + +
Protocols
FromNSURLSessionDataDelegate, NSURLSessionTaskDelegate, SDWebImageDownloaderOperationInterface, SDWebImageOperation
ToSDWebImageDownloaderOperation
+
+
Modified SDWebImageDownloaderOperation.response
+ + + + +
Declaration
From@property (nonatomic, strong, nullable) NSURLResponse *response
To@property (nonatomic, readonly, strong, nullable) NSURLResponse *response
+
+
+ +
+ +
+
SDWebImageDownloaderRequestModifier.h
+ +
+
Added SDWebImageDownloaderRequestModifierBlock
+
Added SDWebImageDownloaderRequestModifier
+
Added -[SDWebImageDownloaderRequestModifier modifiedRequestWithRequest:]
+
Added SDWebImageDownloaderRequestModifier
+
Added -[SDWebImageDownloaderRequestModifier initWithBlock:]
+
Added +[SDWebImageDownloaderRequestModifier requestModifierWithBlock:]
+
+ +
+ +
+
SDWebImageError.h
+ +
+
Added SDWebImageErrorDownloadStatusCodeKey
+
Added SDWebImageError
+
Added SDWebImageErrorInvalidURL
+
Added SDWebImageErrorBadImageData
+
Added SDWebImageErrorCacheNotModified
+
Added SDWebImageErrorInvalidDownloadOperation
+
Added SDWebImageErrorInvalidDownloadStatusCode
+
+ + +
+
Modified SDWebImageErrorDomain
+ + + + +
Declaration
FromNSString *const SDWebImageErrorDomain
ToNSErrorDomain _Nonnull const SDWebImageErrorDomain
+
+
+ +
+ +
+
SDWebImageFrame.h
+ +
+
Removed SDWebImageFrame
+
Removed SDWebImageFrame.image
+
Removed SDWebImageFrame.duration
+
Removed +[SDWebImageFrame frameWithImage:duration:]
+
+ +
+ +
+
SDWebImageGIFCoder.h
+ +
+
Removed SDWebImageGIFCoder
+
Removed +[SDWebImageGIFCoder sharedCoder]
+
+ +
+ +
+
SDWebImageImageIOCoder.h
+ +
+
Removed SDWebImageImageIOCoder
+
Removed +[SDWebImageImageIOCoder sharedCoder]
+
+ +
+ +
+
SDWebImageIndicator.h
+ +
+
Added SDWebImageIndicator
+
Added -[SDWebImageIndicator indicatorView]
+
Added -[SDWebImageIndicator startAnimatingIndicator]
+
Added -[SDWebImageIndicator stopAnimatingIndicator]
+
Added -[SDWebImageIndicator updateIndicatorProgress:]
+
Added SDWebImageActivityIndicator
+
Added SDWebImageActivityIndicator.indicatorView
+
Added SDWebImageActivityIndicator.grayIndicator
+
Added SDWebImageActivityIndicator.grayLargeIndicator
+
Added SDWebImageActivityIndicator.whiteIndicator
+
Added SDWebImageActivityIndicator.whiteLargeIndicator
+
Added SDWebImageProgressIndicator
+
Added SDWebImageProgressIndicator.indicatorView
+
Added SDWebImageProgressIndicator.defaultIndicator
+
Added SDWebImageProgressIndicator.barIndicator
+
+ +
+ +
+
SDWebImageManager.h
+ +
+
Removed SDWebImageCacheMemoryOnly
+
Removed SDWebImageProgressiveDownload
+
Removed SDWebImageQueryDataWhenInMemory
+
Removed SDWebImageQueryDiskSync
+
Removed -[SDWebImageManagerDelegate imageManager:transformDownloadedImage:withURL:]
+
Removed SDWebImageManager.imageDownloader
+
Removed -[SDWebImageManager initWithCache:downloader:]
+
Removed -[SDWebImageManager saveImageToCache:forURL:]
+
Removed -[SDWebImageManager cachedImageExistsForURL:completion:]
+
Removed -[SDWebImageManager diskImageExistsForURL:completion:]
+
+ + +
+
Added SDWebImageCombinedOperation
+
Added -[SDWebImageCombinedOperation cancel]
+
Added SDWebImageCombinedOperation.cacheOperation
+
Added SDWebImageCombinedOperation.loaderOperation
+
Added SDWebImageManager.imageLoader
+
Added SDWebImageManager.transformer
+
Added SDWebImageManager.defaultImageCache
+
Added SDWebImageManager.defaultImageLoader
+
Added -[SDWebImageManager initWithCache:loader:]
+
Added -[SDWebImageManager loadImageWithURL:options:context:progress:completed:]
+
+ + +
+
Modified -[SDWebImageManagerDelegate imageManager:shouldDownloadImageForURL:]
+ + + + +
Declaration
From- (BOOL)imageManager:(nonnull SDWebImageManager *)imageManager shouldDownloadImageForURL:(nullable NSURL *)imageURL
To- (BOOL)imageManager:(nonnull SDWebImageManager *)imageManager shouldDownloadImageForURL:(nonnull NSURL *)imageURL
+
+
Modified SDWebImageManager.imageCache
+ + + + +
Declaration
From@property (nonatomic, readonly, strong, nullable) SDImageCache *imageCache
To@property (nonatomic, readonly, strong, nonnull) id<SDImageCache> imageCache
+
+
Modified SDWebImageManager.cacheKeyFilter
+ + + + +
Declaration
From@property (nonatomic, copy, nullable) SDWebImageCacheKeyFilterBlock cacheKeyFilter
To@property (nonatomic, strong, nullable) id<SDWebImageCacheKeyFilter> cacheKeyFilter
+
+
Modified SDWebImageManager.cacheSerializer
+ + + + +
Declaration
From@property (nonatomic, copy, nullable) SDWebImageCacheSerializerBlock cacheSerializer
To@property (nonatomic, strong, nullable) id<SDWebImageCacheSerializer> cacheSerializer
+
+
Modified -[SDWebImageManager isRunning]
+ + + + +
Declaration
From- (BOOL)isRunning
To@property (nonatomic, readonly, assign, getter=isRunning) BOOL running
+
+
Modified +[SDWebImageManager sharedManager]
+ + + + +
Declaration
From+ (nonnull instancetype)sharedManager
To@property (class, nonatomic, readonly, nonnull) SDWebImageManager *sharedManager
+
+
Modified -[SDWebImageManager loadImageWithURL:options:progress:completed:]
+ + + + +
Declaration
From- (nullable id<SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDInternalCompletionBlock)completedBlock
To- (nullable SDWebImageCombinedOperation *)loadImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nonnull SDInternalCompletionBlock)completedBlock
+
+
+ +
+ +
+
SDWebImageOperation.h
+ +
+
Added NSOperation (SDWebImageOperation)
+
+ +
+ +
+
SDWebImagePrefetcher.h
+ +
+
Removed SDWebImagePrefetcher.maxConcurrentDownloads
+
Removed SDWebImagePrefetcher.prefetcherQueue
+
+ + +
+
Added SDWebImagePrefetchToken
+
Added -[SDWebImagePrefetchToken cancel]
+
Added SDWebImagePrefetchToken.urls
+
Added SDWebImagePrefetcher.context
+
Added SDWebImagePrefetcher.delegateQueue
+
+ + +
+
Modified +[SDWebImagePrefetcher sharedImagePrefetcher]
+ + + + +
Declaration
From+ (nonnull instancetype)sharedImagePrefetcher
To@property (class, nonatomic, readonly, nonnull) SDWebImagePrefetcher *sharedImagePrefetcher
+
+
Modified -[SDWebImagePrefetcher prefetchURLs:]
+ + + + +
Declaration
From- (void)prefetchURLs:(nullable NSArray<NSURL *> *)urls
To- (nullable SDWebImagePrefetchToken *)prefetchURLs:(nullable NSArray<NSURL *> *)urls
+
+
Modified -[SDWebImagePrefetcher prefetchURLs:progress:completed:]
+ + + + +
Declaration
From- (void)prefetchURLs:(nullable NSArray<NSURL *> *)urls progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock
To- (nullable SDWebImagePrefetchToken *)prefetchURLs:(nullable NSArray<NSURL *> *)urls progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock
+
+
+ +
+ +
+
UIButton+WebCache.h
+ +
+
Added -[UIButton sd_setImageWithURL:forState:placeholderImage:options:context:]
+
Added -[UIButton sd_setImageWithURL:forState:placeholderImage:options:progress:completed:]
+
Added -[UIButton sd_setImageWithURL:forState:placeholderImage:options:context:progress:completed:]
+
Added -[UIButton sd_setBackgroundImageWithURL:forState:placeholderImage:options:context:]
+
Added -[UIButton sd_setBackgroundImageWithURL:forState:placeholderImage:options:progress:completed:]
+
Added -[UIButton sd_setBackgroundImageWithURL:forState:placeholderImage:options:context:progress:completed:]
+
+ + +
+
Modified -[UIButton sd_currentImageURL]
+ + + + +
Declaration
From- (nullable NSURL *)sd_currentImageURL
To@property (nonatomic, readonly, strong, nullable) NSURL *sd_currentImageURL
+
+
Modified -[UIButton sd_currentBackgroundImageURL]
+ + + + +
Declaration
From- (nullable NSURL *)sd_currentBackgroundImageURL
To@property (nonatomic, readonly, strong, nullable) NSURL *sd_currentBackgroundImageURL
+
+
+ +
+ +
+
UIImage+ForceDecode.h
+ +
+
Removed +[UIImage decodedImageWithImage:]
+
Removed +[UIImage decodedAndScaledDownImageWithImage:]
+
+ + +
+
Added UIImage.sd_isDecoded
+
Added +[UIImage sd_decodedImageWithImage:]
+
Added +[UIImage sd_decodedAndScaledDownImageWithImage:]
+
Added +[UIImage sd_decodedAndScaledDownImageWithImage:limitBytes:]
+
+ +
+ +
+
UIImage+GIF.h
+ +
+
Removed +[UIImage sd_animatedGIFWithData:]
+
Removed -[UIImage isGIF]
+
+ + +
+
Added +[UIImage sd_imageWithGIFData:]
+
+ +
+ +
+
UIImage+Metadata.h
+ +
+
Added UIImage (Metadata)
+
Added UIImage.sd_isAnimated
+
Added UIImage.sd_isIncremental
+
+ +
+ +
+
UIImage+MultiFormat.h
+ +
+
Added +[UIImage sd_imageWithData:scale:]
+
Added +[UIImage sd_imageWithData:scale:firstFrameOnly:]
+
Added -[UIImage sd_imageDataAsFormat:compressionQuality:]
+
Added -[UIImage sd_imageDataAsFormat:compressionQuality:firstFrameOnly:]
+
+ +
+ +
+
UIImage+Transform.h
+ +
+
Added SDImageScaleMode
+
Added SDImageScaleModeFill
+
Added SDImageScaleModeAspectFit
+
Added SDImageScaleModeAspectFill
+
Added SDRectCorner
+
Added UIImage (Transform)
+
Added -[UIImage sd_resizedImageWithSize:scaleMode:]
+
Added -[UIImage sd_croppedImageWithRect:]
+
Added -[UIImage sd_roundedCornerImageWithRadius:corners:borderWidth:borderColor:]
+
Added -[UIImage sd_rotatedImageWithAngle:fitSize:]
+
Added -[UIImage sd_flippedImageWithHorizontal:vertical:]
+
Added -[UIImage sd_tintedImageWithColor:]
+
Added -[UIImage sd_colorAtPoint:]
+
Added -[UIImage sd_colorsWithRect:]
+
Added -[UIImage sd_blurredImageWithRadius:]
+
Added -[UIImage sd_filteredImageWithFilter:]
+
+ +
+ +
+
UIImageView+HighlightedWebCache.h
+ +
+
Added -[UIImageView sd_setHighlightedImageWithURL:options:context:]
+
Added -[UIImageView sd_setHighlightedImageWithURL:options:context:progress:completed:]
+
+ + +
+
Modified -[UIImageView sd_setHighlightedImageWithURL:options:progress:completed:]
+ + + + +
Declaration
From- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock
To- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock
+
+
+ +
+ +
+
UIImageView+WebCache.h
+ +
+
Removed -[UIImageView sd_setImageWithPreviousCachedImageWithURL:placeholderImage:options:progress:completed:]
+
+ + +
+
Added -[UIImageView sd_setImageWithURL:placeholderImage:options:context:]
+
Added -[UIImageView sd_setImageWithURL:placeholderImage:options:context:progress:completed:]
+
+ + +
+
Modified -[UIImageView sd_setImageWithURL:placeholderImage:options:progress:completed:]
+ + + + +
Declaration
From- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock
To- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock
+
+
+ +
+ +
+
UIView+WebCache.h
+ +
+
Removed SDWebImageInternalSetImageGroupKey
+
Removed SDWebImageExternalCustomManagerKey
+
Removed -[UIView sd_internalSetImageWithURL:placeholderImage:options:operationKey:setImageBlock:progress:completed:]
+
Removed -[UIView sd_internalSetImageWithURL:placeholderImage:options:operationKey:setImageBlock:progress:completed:context:]
+
Removed -[UIView sd_setShowActivityIndicatorView:]
+
Removed -[UIView sd_setIndicatorStyle:]
+
Removed -[UIView sd_showActivityIndicatorView]
+
Removed -[UIView sd_addActivityIndicator]
+
Removed -[UIView sd_removeActivityIndicator]
+
+ + +
+
Added -[UIView sd_internalSetImageWithURL:placeholderImage:options:context:setImageBlock:progress:completed:]
+
Added UIView.sd_imageIndicator
+
+ + +
+
Modified -[UIView sd_imageURL]
+ + + + +
Declaration
From- (nullable NSURL *)sd_imageURL
To@property (nonatomic, readonly, strong, nullable) NSURL *sd_imageURL
+
+
+ +
+ +
+
UIView+WebCacheOperation.h
+ +
+
Added -[UIView sd_imageLoadOperationForKey:]
+
+ +
+ + diff --git a/Docs/SDWebImage-5.0-Migration-guide.md b/Docs/SDWebImage-5.0-Migration-guide.md index 936e42e2..7253f5a4 100644 --- a/Docs/SDWebImage-5.0-Migration-guide.md +++ b/Docs/SDWebImage-5.0-Migration-guide.md @@ -10,51 +10,77 @@ This guide is provided in order to ease the transition of existing applications SDWebImage 5.0 officially supports iOS 8 and later, Mac OS X 10.10 and later, watchOS 2 and later and tvOS 9 and later. It needs Xcode 9 or later to be able to build everything properly. -For targeting previous versions of the SDKs, check [README - Backwards compatibility](https://github.com/rs/SDWebImage#backwards-compatibility) -. +For targeting previous versions of the SDKs, check [README - Backwards compatibility](https://github.com/rs/SDWebImage#backwards-compatibility). ### Migration -#### Swift +Using the view categories brings no change from 4.x to 5.0. -- TBD if needed - +Objective-C: -#### Objective-C +```objective-c +[imageView sd_setImageWithURL:url placeholderImage:placeholderImage]; +``` -- TBD if needed - +Swift: -### FLAnimatedImage support moved to a dedicated plugin repo -We are no longer hosting the integration with `FLAnimatedImage` inside this repo. We have a dedicated repo for that. -TBD +```swift +imageView.sd_setImage(with: url, placeholderImage: placeholder) +``` -### Entities +However, all view categories in 5.0 introduce a new extra arg called `SDWebImageContext`. Which can hold anything that previous enum `SDWebImageOptions` can not. This allow user to control advanced behavior for view loading as well as many aspect. See the declaration for `SDWebImageContext` for detailed information. + +### New Features + +#### Animated Image View + +In 5.0, we introduce a brand new animated image solution. Which including animated image loading, rendering, decoding, and also support customization for advanced user. + +This animated image solution is available for iOS/tvOS/macOS. The `SDAnimatedImage` is subclass of `UIImage/NSImage`, and `SDAnimatedImageView` is subclass of `UIImageView/NSImageView`, to allow most compatible for common framework APIs. See [Animated Image](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#animated-image-50) for more detailed information. + +#### Transformer + +In 5.0, we introduce a easy way to provide a image transform process after the image was downloaded from network. Which allow user to easily scale, rotate, rounded corner the original image. And even support chain a list of transformers together to output the final one. These transformed image will also stored to cache to avoid duplicate process. See [Image Transformer](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#transformer-50) for more detailed information. + +#### Customization + +In 5.0, we refactor our framework architecture, to allow it easy to customize for advanced user, without breaking anything or create their fork. We introduce [Custom Cache](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-cache-50), [Custom Loader](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-loader-50), and make current [Custom Coder](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-coder-420) works better for these developers. + +#### FLAnimatedImage support moved to a dedicated plugin repo + +Since we introduce the new animated image solution. Now we are no longer hosting the integration with `FLAnimatedImage` inside this repo. But for user who need `FLAnimatedImage` support. We have a dedicated repo for that and contains all the code compatible for SDWebImage 5.0. See [SDWebImageFLPlugin](https://github.com/SDWebImage/SDWebImageFLPlugin) for more detailed information. + +#### Photos Plugin + +By taking the advantage of [Custom Loader](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-loader-50) feature, we introduce a plugin to allow easily load Photos Library images. See [SDWebImagePhotosPlugin](https://github.com/SDWebImage/SDWebImagePhotosPlugin) for more detailed information. + + +### API Changes #### SDImageCache -- new initializer `initWithNamespace:diskCacheDirectory:config:`, is now the designated initializer - moved `maxMemoryCost` and `maxMemoryCountLimit` to `SDImageCacheConfig` -- added `SDImageCache diskImageDataExistsWithKey:` synchronous method +- `makeDiskCachePath:` removed, use `NSSearchPathForDirectoriesInDomains` with NSString's Path API instead. - `addReadOnlyCachePath:` removed, use `additionalCachePathBlock` instead - `cachePathForKey:inPath:` removed, use `cachePathForKey:` with NSString's path API instead. - `defaultCachePathForKey:` removed, use `cachePathForKey:` instead +- `SDCacheQueryCompletedBlock` renamed to `SDImageCacheQueryCompletionBlock` +- `SDWebImageCheckCacheCompletionBlock` renamed to `SDImageCacheCheckCompletionBlock` +- `SDWebImageCalculateSizeBlock` renamed to `SDImageCacheCalculateSizeBlock` #### SDImageCacheConfig -- added `diskCacheWritingOptions` of type `NSDataWritingOptions`, defaults to `NSDataWritingAtomic` -- added `maxMemoryCost` and `maxMemoryCountLimit` properties (used to be in `SDImageCache`) - `shouldDecompressImages` removed. Use `SDImageCacheAvoidDecodeImage` in cache options instead #### SDWebImageManager - `loadImageWithURL:options:progress:completed:` changed the `completed` param requirement from `nullable` to `nonnull` - `loadImageWithURL:options:progress:completed:` return type `id` changed to `SDWebImageCombinedOperation *` -- `shared()` changed to `shared` -- `isRunning()` changed to `isRunning` -- `imageCache` changed from nullable to nonnull -- `imageDownloader` renamed to `imageLoader` and changed from nullable to nonnull -- `cacheKeyFilter` property type changed to `id`, use the `SDWebImageCacheKeyFilter cacheKeyFilterWithBlock:` -- `cacheSerializer` property type CHANGED to `id`, use the `SDWebImageCacheSerializer cacheSerializerWithBlock:` -- `imageCache` property type changed from `SDImageCache *` to `id`. The default value does not change. +- `imageCache` changed from nullable to nonnull. And property type changed from `SDImageCache *` to `id`. The default value does not change. +- `imageDownloader` renamed to `imageLoader` and changed from nullable to nonnull. And property type changed from `SDWebImageDownloader *` to `id`. The default value does not change. +- `cacheKeyFilter` property type changed to `id`, you can use `+[SDWebImageCacheKeyFilter cacheKeyFilterWithBlock:]` to create +- `cacheSerializer` property type changed to `id`, you can use `+[SDWebImageCacheSerializer cacheSerializerWithBlock:]` to create +- `SDWebImageCacheKeyFilterBlock`'s `url` arg change from nullable to nonnull - `initWithCache:downloader:` 's `cache` arg type changed from `SDImageCache *` to `id` - `initWithCache:downloader` renamed to `initWithCache:loader:` - `saveImageToCache:forURL:` removed. Use `SDImageCache storeImage:imageData:forKey:cacheType:completion:` (or `SDImageCache storeImage:forKey:toDisk:completion:` if you use default cache class) with `cacheKeyForURL:` instead. @@ -63,25 +89,26 @@ TBD #### SDWebImageManagerDelegate -- removed `imageManager:transformDownloadedImage:forKey:` +- removed `imageManager:transformDownloadedImage:forKey:`, use `SDImageTransformer` with context option instead #### UIView and subclasses (UIImageView, UIButton, ...) - `sd_internalSetImageWithURL:placeholderImage:options:operationKey:setImageBlock:progress:completed:` renamed to `UIView sd_internalSetImageWithURL:placeholderImage:options:context:setImageBlock:progress:completed:` (The biggest changes is that the completion block type from `SDExternalCompletionBlock` to `SDInternalCompletionBlock`. Which allow advanced user to get more information of image loading process) - `sd_internalSetImageWithURL:placeholderImage:options:operationKey:setImageBlock:progress:completed:context:` removed - activity indicator refactoring - use `sd_imageIndicator` with `SDWebImageActivityIndicator` - - `sd_setShowActivityIndicatorView:` removed - - `sd_setIndicatorStyle:` removed - - `sd_showActivityIndicatorView` removed - - `sd_addActivityIndicator:` removed - - `sd_removeActivityIndicator:` removed +- `sd_setShowActivityIndicatorView:` removed +- `sd_setIndicatorStyle:` removed +- `sd_showActivityIndicatorView` removed +- `sd_addActivityIndicator:` removed +- `sd_removeActivityIndicator:` removed #### UIImage - Renamed `isGIF` to `sd_isAnimated`, also `NSImage isGIF` renamed to `NSImage sd_isAnimated` - Renamed `decodedImageWithImage:` to `sd_decodedImageWithImage:` - Renamed `decodedAndScaledDownImageWithImage:` to `sd_decodedAndScaledDownImageWithImage:` -- Removed `sd_webpLoopCount` since we have `sd_imageLoopCount` +- Renamed `sd_animatedGIFWithData` to `sd_imageWithGIFData:` +- Removed `sd_webpLoopCount` #### UIImageView @@ -89,9 +116,6 @@ TBD #### SDWebImageDownloader -- `shared()` changed to `shared` -- `setOperationClass` available for Swift user -- `setSuspended(_:)` changed to `isSuspended` property - `shouldDecompressImages` moved to `SDWebImageDownloaderConfig.shouldDecompressImages` - `maxConcurrentDownloads` moved to `SDWebImageDownloaderConfig.maxConcurrentDownloads` - `downloadTimeout` moved to `SDWebImageDownloaderConfig.downloadTimeout` @@ -100,10 +124,10 @@ TBD - `urlCredential` moved to `SDWebImageDownloaderConfig.urlCredential` - `username` moved to `SDWebImageDownloaderConfig.username` - `password` moved to `SDWebImageDownloaderConfig.password` -- `initWithSessionConfiguration:` removed, use `initWithConfig:]` with session configuration instead -- `createNewSessionWithConfiguration:` removed, use `initWithConfig:]` with new session configuration instead. To modify shared downloader configuration, provide custom `SDWebImageDownloaderConfig.defaultDownloaderConfig` before it created. +- `initWithSessionConfiguration:` removed, use `initWithConfig:` with session configuration instead +- `createNewSessionWithConfiguration:` removed, use `initWithConfig:` with new session configuration instead. To modify shared downloader configuration, provide custom `SDWebImageDownloaderConfig.defaultDownloaderConfig` before it created. - `headersFilter` removed, use `requestModifier` instead -- `cancel:` removed, use `SDWebImageDownloadToken cancel` instead +- `cancel:` removed, use `-[SDWebImageDownloadToken cancel]` instead - `shouldDecompressImages` removed. Use `SDWebImageDownloaderAvoidDecodeImage` in downloader options instead - use `SDWebImageLoaderProgressBlock` instead of `SDWebImageDownloaderProgressBlock` - use `SDWebImageLoaderCompletedBlock` instead of `SDWebImageDownloaderCompletedBlock` @@ -112,9 +136,10 @@ TBD - `initWithRequest:inSession:options:context:` is now the designated initializer - Removed `shouldUseCredentialStorage` property -- `SDWebImageDownloadOperationInterface` protocol renamed to `SDWebImageDownloadOperation`. (`SDWebImageDownloadOperationProtocol` for Swift) +- `SDWebImageDownloadOperationInterface` protocol renamed to `SDWebImageDownloadOperation` - `expectedSize` removed, use `response.expectedContentLength` instead - `shouldDecompressImages` removed. Use `SDWebImageDownloaderAvoidDecodeImage` in downloader options instead. +- `response` property change to readonly #### SDWebImagePrefetcher @@ -123,13 +148,36 @@ TBD - `maxConcurrentDownloads` property removed, use `SDWebImageManager.downloader` config instead #### SDImageCoder -- `SDCGColorSpaceGetDeviceRGB()` moved to `SDImageCoderHelper colorSpaceGetDeviceRGB` -- `SDCGImageRefContainsAlpha()`, moved to `SDImageCoderHelper imageRefContainsAlpha:` +- `SDCGColorSpaceGetDeviceRGB()` moved to `+[SDImageCoderHelper colorSpaceGetDeviceRGB]` +- `SDCGImageRefContainsAlpha()`, moved to `+[SDImageCoderHelper imageRefContainsAlpha:]` - `decodedImageWithData:` replaced with `decodedImageWithData:options:` - `encodedDataWithImage:format:` replaced with `encodedDataWithImage:format:options` - `init` method from `SDWebImageProgressiveCoder` changed to `initIncrementalWithOptions:` -- `incrementalDecodedImageWithData:finished` replaced with `updateIncrementalData:finished` and `incrementalDecodedImageWithOptions:` -- removed `decompressedImage:data:options` +- `incrementalDecodedImageWithData:finished` replaced with `updateIncrementalData:finished` and `incrementalDecodedImageWithOptions:` two APIs +- removed `decompressedImage:data:options`, use `+[SDImageCoderHelper decodedImageWithImage:]` and `+[SDImageCoderHelper decodedAndScaledDownImageWithImage:limitBytes:]` instead + +#### Constants + +- `SDWebImageInternalSetImageGroupKey` renamed to `SDWebImageContextSetImageGroup` +- `SDWebImageExternalCustomManagerKey` renamed to `SDWebImageContextCustomManager` + +### Swift Specific API Changes +We did a full cleanup of the Swift APIs. We are using many modern Objective-C declarations to generate the Swift API. We now provide full nullability support, string enum, class property, and even custom Swift API name, all to make the framework easier to use for our Swift users. Here are the API change specify for Swift. + +#### UIView+WebCache +- `sd_imageURL()` changed to `sd_imageURL` + +#### SDWebImageManager +- `shared()` changed to `shared` +- `isRunning()` changed to `isRunning` + +#### SDWebImageDownloader +- `shared()` changed to `shared` +- `setOperationClass(_:)` available for Swift user with `operationClass` property +- `setSuspended(_:)` changed to `isSuspended` property + +#### SDWebImageDownloadOperation +- `SDWebImageDownloadOperationInterface` protocol renamed to `SDWebImageDownloadOperationProtocol`. #### SDImageCodersManager @@ -154,13 +202,12 @@ TBD #### UIButton-WebCache - `sd_currentImageURL()` changed to `sd_currentImageURL` - + #### NSButton-WebCache - `sd_currentImageURL()` changed to `sd_currentImageURL` - `sd_currentAlternateImageURL()` changed to `sd_currentAlternateImageURL` -#### Constants +### Full API Diff +For advanced user who need the detailed API diff, we provide the full diff in a HTML web page: [SDWebImage 5.0 API Diff](API-Diff/5.0/apidiff.html) -- `SDWebImageInternalSetImageGroupKey` renamed to `SDWebImageContextSetImageGroup` -- `SDWebImageExternalCustomManagerKey` renamed to `SDWebImageContextCustomManager` From f8fe88633495f9a95560ed9160d0634f04c071ae Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Thu, 12 Jul 2018 21:10:28 +0300 Subject: [PATCH 207/361] Instead of defining `LOCK` and `UNLOCK` macros in each file, moved them to the `SDWebImageCompat.h`. Also, split into `LOCK` and `LOCKBLOCK` --- SDWebImage/SDAnimatedImage.m | 10 +++------- SDWebImage/SDAnimatedImageView.m | 18 +++++++----------- SDWebImage/SDImageCodersManager.m | 3 --- SDWebImage/SDImageLoadersManager.m | 3 --- SDWebImage/SDMemoryCache.m | 3 --- SDWebImage/SDWebImageCompat.h | 14 ++++++++++++++ SDWebImage/SDWebImageDownloader.m | 3 --- SDWebImage/SDWebImageDownloaderOperation.m | 3 --- SDWebImage/SDWebImageManager.m | 3 --- SDWebImage/WebP/SDImageWebPCoder.m | 6 +----- 10 files changed, 25 insertions(+), 41 deletions(-) diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index d05a430c..fa20c898 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -12,10 +12,6 @@ #import "SDImageCodersManager.h" #import "SDImageFrame.h" -#define LOCK(...) dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER); \ -__VA_ARGS__; \ -dispatch_semaphore_signal(self->_lock); - static CGFloat SDImageScaleFromPath(NSString *string) { if (string.length == 0 || [string hasSuffix:@"/"]) return 1; NSString *name = string.stringByDeletingPathExtension; @@ -108,7 +104,7 @@ static NSArray *SDBundlePreferredScales() { } - (void)didReceiveMemoryWarning:(NSNotification *)notification { - LOCK({ + LOCKBLOCK({ [self.imageTable removeAllObjects]; }); } @@ -178,7 +174,7 @@ static NSArray *SDBundlePreferredScales() { - (UIImage *)imageForName:(NSString *)name { NSParameterAssert(name); UIImage *image; - LOCK({ + LOCKBLOCK({ image = [self.imageTable objectForKey:name]; }); return image; @@ -187,7 +183,7 @@ static NSArray *SDBundlePreferredScales() { - (void)storeImage:(UIImage *)image forName:(NSString *)name { NSParameterAssert(image); NSParameterAssert(name); - LOCK({ + LOCKBLOCK({ [self.imageTable setObject:image forKey:name]; }); } diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index a848cade..ebbffd78 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -38,10 +38,6 @@ static NSUInteger SDDeviceFreeMemory() { return vm_stat.free_count * page_size; } -#define LOCK(...) dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER); \ -__VA_ARGS__; \ -dispatch_semaphore_signal(self->_lock); - @interface SDWeakProxy : NSProxy @property (nonatomic, weak, readonly) id target; @@ -242,7 +238,7 @@ dispatch_semaphore_signal(self->_lock); self.animatedImageScale = 1; [_fetchQueue cancelAllOperations]; _fetchQueue = nil; - LOCK({ + LOCKBLOCK({ [_frameBuffer removeAllObjects]; _frameBuffer = nil; }); @@ -303,7 +299,7 @@ dispatch_semaphore_signal(self->_lock); self.animatedImageScale = image.scale; if (!self.isProgressive) { self.currentFrame = image; - LOCK({ + LOCKBLOCK({ self.frameBuffer[@(self.currentFrameIndex)] = self.currentFrame; }); } @@ -424,7 +420,7 @@ dispatch_semaphore_signal(self->_lock); [_fetchQueue cancelAllOperations]; [_fetchQueue addOperationWithBlock:^{ NSNumber *currentFrameIndex = @(self.currentFrameIndex); - LOCK({ + LOCKBLOCK({ NSArray *keys = self.frameBuffer.allKeys; // only keep the next frame for later rendering for (NSNumber * key in keys) { @@ -681,12 +677,12 @@ dispatch_semaphore_signal(self->_lock); // Update the current frame UIImage *currentFrame; - LOCK({ + LOCKBLOCK({ currentFrame = self.frameBuffer[@(currentFrameIndex)]; }); BOOL bufferFull = NO; if (currentFrame) { - LOCK({ + LOCKBLOCK({ // Remove the frame buffer if need if (self.frameBuffer.count > self.maxBufferCount) { self.frameBuffer[@(currentFrameIndex)] = nil; @@ -710,7 +706,7 @@ dispatch_semaphore_signal(self->_lock); if (self.isProgressive) { // Recovery the current frame index and removed frame buffer (See above) self.currentFrameIndex = currentFrameIndex; - LOCK({ + LOCKBLOCK({ self.frameBuffer[@(currentFrameIndex)] = self.currentFrame; }); [self stopAnimating]; @@ -740,7 +736,7 @@ dispatch_semaphore_signal(self->_lock); UIImage *animatedImage = self.animatedImage; NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ UIImage *fetchFrame = [animatedImage animatedImageFrameAtIndex:fetchFrameIndex]; - LOCK({ + LOCKBLOCK({ self.frameBuffer[@(fetchFrameIndex)] = fetchFrame; }); }]; diff --git a/SDWebImage/SDImageCodersManager.m b/SDWebImage/SDImageCodersManager.m index 83da2455..131925d1 100644 --- a/SDWebImage/SDImageCodersManager.m +++ b/SDWebImage/SDImageCodersManager.m @@ -14,9 +14,6 @@ #import "SDImageWebPCoder.h" #endif -#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); -#define UNLOCK(lock) dispatch_semaphore_signal(lock); - @interface SDImageCodersManager () @property (nonatomic, strong, nonnull) dispatch_semaphore_t codersLock; diff --git a/SDWebImage/SDImageLoadersManager.m b/SDWebImage/SDImageLoadersManager.m index c53e4247..0e0a0c5d 100644 --- a/SDWebImage/SDImageLoadersManager.m +++ b/SDWebImage/SDImageLoadersManager.m @@ -9,9 +9,6 @@ #import "SDImageLoadersManager.h" #import "SDWebImageDownloader.h" -#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); -#define UNLOCK(lock) dispatch_semaphore_signal(lock); - @interface SDImageLoadersManager () @property (nonatomic, strong, nonnull) dispatch_semaphore_t loadersLock; diff --git a/SDWebImage/SDMemoryCache.m b/SDWebImage/SDMemoryCache.m index 6562185b..e434f4ec 100644 --- a/SDWebImage/SDMemoryCache.m +++ b/SDWebImage/SDMemoryCache.m @@ -9,9 +9,6 @@ #import "SDMemoryCache.h" #import "SDImageCacheConfig.h" -#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); -#define UNLOCK(lock) dispatch_semaphore_signal(lock); - NSUInteger SDMemoryCacheCostForImage(UIImage * _Nullable image) { #if SD_MAC return image.size.height * image.size.width; diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index f47a248a..c58cbdab 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -93,3 +93,17 @@ dispatch_async(dispatch_get_main_queue(), block);\ } #endif + +#ifndef LOCK +#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); +#endif + +#ifndef UNLOCK +#define UNLOCK(lock) dispatch_semaphore_signal(lock); +#endif + +#ifndef LOCKBLOCK +#define LOCKBLOCK(...) dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER); \ +__VA_ARGS__; \ +dispatch_semaphore_signal(self->_lock); +#endif diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 8e0f89bb..7dd3c7aa 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -13,9 +13,6 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; -#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); -#define UNLOCK(lock) dispatch_semaphore_signal(lock); - @interface SDWebImageDownloadToken () @property (nonatomic, strong, nullable, readwrite) NSURL *url; diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index a687367d..5232400b 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -9,9 +9,6 @@ #import "SDWebImageDownloaderOperation.h" #import "SDWebImageError.h" -#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); -#define UNLOCK(lock) dispatch_semaphore_signal(lock); - // iOS 8 Foundation.framework extern these symbol but the define is in CFNetwork.framework. We just fix this without import CFNetwork.framework #if (__IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0) const float NSURLSessionTaskPriorityHigh = 0.75; diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 85f57d36..9e0adb05 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -12,9 +12,6 @@ #import "UIImage+Metadata.h" #import "SDWebImageError.h" -#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); -#define UNLOCK(lock) dispatch_semaphore_signal(lock); - static id _defaultImageCache; static id _defaultImageLoader; diff --git a/SDWebImage/WebP/SDImageWebPCoder.m b/SDWebImage/WebP/SDImageWebPCoder.m index f2171a7c..c6366162 100644 --- a/SDWebImage/WebP/SDImageWebPCoder.m +++ b/SDWebImage/WebP/SDImageWebPCoder.m @@ -26,10 +26,6 @@ #endif #import -#define LOCK(...) dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER); \ -__VA_ARGS__; \ -dispatch_semaphore_signal(self->_lock); - @interface SDWebPCoderFrame : NSObject @property (nonatomic, assign) NSUInteger index; // Frame index (zero based) @@ -741,7 +737,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { if (index >= _frameCount) { return nil; } - LOCK({ + LOCKBLOCK({ image = [self safeAnimatedImageFrameAtIndex:index]; }); return image; From 982ade8824adbd5a2ea39bd5f27cd4809400b612 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 13 Jul 2018 22:17:02 +0800 Subject: [PATCH 208/361] Remove all FLAnimatedImage from the Core SDWebImage repo. Move the code to SDWebImageFLPlugin repo --- .gitmodules | 3 - SDWebImage.podspec | 12 +- SDWebImage.xcodeproj/project.pbxproj | 73 -------- .../FLAnimatedImageView+WebCache.h | 168 ----------------- .../FLAnimatedImageView+WebCache.m | 175 ------------------ SDWebImage/SDImageCodersManager.h | 2 +- SDWebImage/SDImageIOCoder.h | 2 +- Tests/Podfile | 1 - .../project.pbxproj | 6 +- Tests/Tests/SDImageCoderTests.m | 2 +- Tests/Tests/SDWebCacheCategoriesTests.m | 19 -- Vendors/FLAnimatedImage | 1 - WebImage/SDWebImage.h | 6 - 13 files changed, 6 insertions(+), 464 deletions(-) delete mode 100644 SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.h delete mode 100644 SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m delete mode 160000 Vendors/FLAnimatedImage diff --git a/.gitmodules b/.gitmodules index d8c3ae83..ce6396d4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "Vendors/libwebp"] path = Vendors/libwebp url = https://github.com/webmproject/libwebp -[submodule "Vendors/FLAnimatedImage"] - path = Vendors/FLAnimatedImage - url = https://github.com/Flipboard/FLAnimatedImage diff --git a/SDWebImage.podspec b/SDWebImage.podspec index f78dbe94..50147bbb 100644 --- a/SDWebImage.podspec +++ b/SDWebImage.podspec @@ -29,7 +29,7 @@ Pod::Spec.new do |s| s.subspec 'Core' do |core| core.source_files = 'SDWebImage/*.{h,m}', 'WebImage/SDWebImage.h' - core.exclude_files = 'SDWebImage/MapKit/*.{h,m}', 'SDWebImage/WebP/*.{h,m}', 'SDWebImage/FLAnimatedImage/*.{h,m}' + core.exclude_files = 'SDWebImage/MapKit/*.{h,m}', 'SDWebImage/WebP/*.{h,m}' end s.subspec 'MapKit' do |mk| @@ -41,16 +41,6 @@ Pod::Spec.new do |s| mk.dependency 'SDWebImage/Core' end - s.subspec 'GIF' do |gif| - gif.ios.deployment_target = '8.0' - gif.source_files = 'SDWebImage/FLAnimatedImage/*.{h,m}' - gif.dependency 'SDWebImage/Core' - gif.dependency 'FLAnimatedImage', '~> 1.0' - gif.xcconfig = { - 'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/FLAnimatedImage/FLAnimatedImage' - } - end - s.subspec 'WebP' do |webp| webp.source_files = 'SDWebImage/WebP/*.{h,m}' webp.xcconfig = { diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index b87f9506..06882856 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -783,24 +783,6 @@ 43C892A31D9D6DDD0022038D /* demux.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892991D9D6DD70022038D /* demux.c */; }; 43C892A41D9D6DDD0022038D /* demux.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892991D9D6DD70022038D /* demux.c */; }; 43C892A51D9D6DDE0022038D /* demux.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892991D9D6DD70022038D /* demux.c */; }; - 43CE75761CFE9427006C64D0 /* FLAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43CE75771CFE9427006C64D0 /* FLAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43CE75781CFE9427006C64D0 /* FLAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43CE75791CFE9427006C64D0 /* FLAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE754A1CFE9427006C64D0 /* FLAnimatedImage.m */; }; - 43CE757A1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE754A1CFE9427006C64D0 /* FLAnimatedImage.m */; }; - 43CE757B1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE754A1CFE9427006C64D0 /* FLAnimatedImage.m */; }; - 43CE757C1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE754B1CFE9427006C64D0 /* FLAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43CE757D1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE754B1CFE9427006C64D0 /* FLAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43CE757E1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE754B1CFE9427006C64D0 /* FLAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43CE757F1CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE754C1CFE9427006C64D0 /* FLAnimatedImageView.m */; }; - 43CE75801CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE754C1CFE9427006C64D0 /* FLAnimatedImageView.m */; }; - 43CE75811CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE754C1CFE9427006C64D0 /* FLAnimatedImageView.m */; }; - 43CE75D01CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75CE1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43CE75D11CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75CE1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43CE75D21CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75CE1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43CE75D31CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE75CF1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m */; }; - 43CE75D41CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE75CF1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m */; }; - 43CE75D51CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE75CF1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m */; }; 4A2CAE041AB4BB5400B6BC39 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4A2CAE181AB4BB6400B6BC39 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D88148C56230056699D /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4A2CAE191AB4BB6400B6BC39 /* SDWebImageCompat.m in Sources */ = {isa = PBXBuildFile; fileRef = 5340674F167780C40042B59E /* SDWebImageCompat.m */; }; @@ -1652,12 +1634,6 @@ 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageCacheConfig.m; sourceTree = ""; }; 43C892981D9D6DD70022038D /* anim_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = anim_decode.c; sourceTree = ""; }; 43C892991D9D6DD70022038D /* demux.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = demux.c; sourceTree = ""; }; - 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLAnimatedImage.h; sourceTree = ""; }; - 43CE754A1CFE9427006C64D0 /* FLAnimatedImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLAnimatedImage.m; sourceTree = ""; }; - 43CE754B1CFE9427006C64D0 /* FLAnimatedImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLAnimatedImageView.h; sourceTree = ""; }; - 43CE754C1CFE9427006C64D0 /* FLAnimatedImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLAnimatedImageView.m; sourceTree = ""; }; - 43CE75CE1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FLAnimatedImageView+WebCache.h"; sourceTree = ""; }; - 43CE75CF1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "FLAnimatedImageView+WebCache.m"; sourceTree = ""; }; 4A2CADFF1AB4BB5300B6BC39 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4A2CAE021AB4BB5400B6BC39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImage.h; sourceTree = ""; }; @@ -2029,35 +2005,6 @@ path = demux; sourceTree = ""; }; - 43CE75451CFE9427006C64D0 /* FLAnimatedImage */ = { - isa = PBXGroup; - children = ( - 43CE75481CFE9427006C64D0 /* FLAnimatedImage */, - ); - name = FLAnimatedImage; - path = Vendors/FLAnimatedImage; - sourceTree = ""; - }; - 43CE75481CFE9427006C64D0 /* FLAnimatedImage */ = { - isa = PBXGroup; - children = ( - 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */, - 43CE754A1CFE9427006C64D0 /* FLAnimatedImage.m */, - 43CE754B1CFE9427006C64D0 /* FLAnimatedImageView.h */, - 43CE754C1CFE9427006C64D0 /* FLAnimatedImageView.m */, - ); - path = FLAnimatedImage; - sourceTree = ""; - }; - 43CE75CD1CFE98B3006C64D0 /* FLAnimatedImage */ = { - isa = PBXGroup; - children = ( - 43CE75CE1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h */, - 43CE75CF1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m */, - ); - path = FLAnimatedImage; - sourceTree = ""; - }; 4A2CAE001AB4BB5300B6BC39 /* WebImage */ = { isa = PBXGroup; children = ( @@ -2103,7 +2050,6 @@ 53922D71148C55820056699D /* Frameworks */ = { isa = PBXGroup; children = ( - 43CE75451CFE9427006C64D0 /* FLAnimatedImage */, DA577C121998E60B007367ED /* libwebp */, 53FB893F14D35D1A0020B787 /* CoreGraphics.framework */, 53922D72148C55820056699D /* Foundation.framework */, @@ -2127,7 +2073,6 @@ 4369C2851D9811BB007E863A /* WebCache Categories */, 32FDE8792088871B008D7530 /* MapKit */, 32FDE88420888726008D7530 /* WebP */, - 43CE75CD1CFE98B3006C64D0 /* FLAnimatedImage */, ); path = SDWebImage; sourceTree = ""; @@ -2424,7 +2369,6 @@ 4317395B1CDFC8B70008FEB9 /* types.h in Headers */, 80377C531F2F666300F89830 /* huffman_utils.h in Headers */, 32FDE8822088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, - 43CE75D21CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */, 431739551CDFC8B70008FEB9 /* decode.h in Headers */, 00733A731BC4880E00A5A117 /* SDWebImage.h in Headers */, 323F8B651F38EF770092B609 /* cost_enc.h in Headers */, @@ -2456,12 +2400,10 @@ 32CF1C0A1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, 80377C4D1F2F666300F89830 /* endian_inl_utils.h in Headers */, 431739581CDFC8B70008FEB9 /* format_constants.h in Headers */, - 43CE75781CFE9427006C64D0 /* FLAnimatedImage.h in Headers */, 00733A6E1BC4880E00A5A117 /* UIImage+MultiFormat.h in Headers */, 323F8B891F38EF770092B609 /* histogram_enc.h in Headers */, 80377EC21F2F66D500F89830 /* vp8i_dec.h in Headers */, 80377EBA1F2F66D500F89830 /* common_dec.h in Headers */, - 43CE757E1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, 3248476C201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 32FDE89820888726008D7530 /* UIImage+WebP.h in Headers */, 80377C5F1F2F666300F89830 /* utils.h in Headers */, @@ -2789,7 +2731,6 @@ 80377C3D1F2F666300F89830 /* quant_levels_utils.h in Headers */, 323F8B521F38EF770092B609 /* backward_references_enc.h in Headers */, 4317394F1CDFC8B70008FEB9 /* demux.h in Headers */, - 43CE757D1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, 32D122202080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AC2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, @@ -2821,7 +2762,6 @@ 4A2CAE181AB4BB6400B6BC39 /* SDWebImageCompat.h in Headers */, 32FDE8812088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, 80377D961F2F66A700F89830 /* msa_macro.h in Headers */, - 43CE75D11CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */, 80377C391F2F666300F89830 /* huffman_utils.h in Headers */, 4A2CAE331AB4BB7500B6BC39 /* UIImageView+HighlightedWebCache.h in Headers */, 431739521CDFC8B70008FEB9 /* mux.h in Headers */, @@ -2832,7 +2772,6 @@ 323F8BDA1F38EF770092B609 /* vp8i_enc.h in Headers */, 4317394E1CDFC8B70008FEB9 /* decode.h in Headers */, 80377C2C1F2F666300F89830 /* bit_reader_inl_utils.h in Headers */, - 43CE75771CFE9427006C64D0 /* FLAnimatedImage.h in Headers */, 4A2CAE2B1AB4BB7500B6BC39 /* UIButton+WebCache.h in Headers */, 4A2CAE251AB4BB7000B6BC39 /* SDWebImagePrefetcher.h in Headers */, 80377C431F2F666300F89830 /* thread_utils.h in Headers */, @@ -2906,7 +2845,6 @@ 80377D0C1F2F66A100F89830 /* msa_macro.h in Headers */, 3290FA041FA478AF0047D20C /* SDImageFrame.h in Headers */, 80377D1D1F2F66A100F89830 /* yuv.h in Headers */, - 43CE75D01CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */, 807A12281F89636300EC2A9B /* SDImageCodersManager.h in Headers */, 32B9B537206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 80377C051F2F665300F89830 /* huffman_utils.h in Headers */, @@ -2953,7 +2891,6 @@ 80377CFD1F2F66A100F89830 /* lossless_common.h in Headers */, 431738C01CDFC2660008FEB9 /* format_constants.h in Headers */, 323F8B621F38EF770092B609 /* cost_enc.h in Headers */, - 43CE75761CFE9427006C64D0 /* FLAnimatedImage.h in Headers */, 323F8BE41F38EF770092B609 /* vp8li_enc.h in Headers */, 32FDE88F20888726008D7530 /* SDImageWebPCoder.h in Headers */, 320CAE152086F50500CFFC80 /* SDWebImageError.h in Headers */, @@ -2965,7 +2902,6 @@ 32484763201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80377E911F2F66D000F89830 /* vp8_dec.h in Headers */, 323F8B6E1F38EF770092B609 /* delta_palettization_enc.h in Headers */, - 43CE757C1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, 32D1221E2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 80377E8A1F2F66D000F89830 /* common_dec.h in Headers */, AB615303192DA24600A2D8E9 /* UIView+WebCacheOperation.h in Headers */, @@ -3222,7 +3158,6 @@ 323F8BC91F38EF770092B609 /* syntax_enc.c in Sources */, 80377DC01F2F66A700F89830 /* enc_mips_dsp_r2.c in Sources */, 80377DA91F2F66A700F89830 /* alpha_processing_neon.c in Sources */, - 43CE75D51CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */, 320CAE1E2086F50500CFFC80 /* SDWebImageError.m in Sources */, 80377DB71F2F66A700F89830 /* dec_mips_dsp_r2.c in Sources */, 80377DC31F2F66A700F89830 /* enc_neon.c in Sources */, @@ -3315,7 +3250,6 @@ 80377DC91F2F66A700F89830 /* filters_neon.c in Sources */, 80377DC51F2F66A700F89830 /* enc_sse41.c in Sources */, 80377DE61F2F66A700F89830 /* upsampling_sse2.c in Sources */, - 43CE75811CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */, 80377C561F2F666300F89830 /* quant_levels_utils.c in Sources */, 323F8BCF1F38EF770092B609 /* token_enc.c in Sources */, 80377DD11F2F66A700F89830 /* lossless_enc_sse2.c in Sources */, @@ -3349,7 +3283,6 @@ 80377DB21F2F66A700F89830 /* cost_mips32.c in Sources */, 32EB6D90206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, 80377DC81F2F66A700F89830 /* filters_msa.c in Sources */, - 43CE757B1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, 00733A571BC4880000A5A117 /* SDImageCache.m in Sources */, 4369C2811D9807EC007E863A /* UIView+WebCache.m in Sources */, 00733A5E1BC4880000A5A117 /* UIImage+MultiFormat.m in Sources */, @@ -3905,14 +3838,12 @@ 32F7C0772030114C00873181 /* SDImageTransformer.m in Sources */, 43C8929D1D9D6DD90022038D /* anim_decode.c in Sources */, 323F8B6A1F38EF770092B609 /* delta_palettization_enc.c in Sources */, - 43CE75D41CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */, 323F8B5E1F38EF770092B609 /* cost_enc.c in Sources */, 80377D8A1F2F66A700F89830 /* lossless_enc_msa.c in Sources */, 80377EA91F2F66D400F89830 /* buffer_dec.c in Sources */, 80377C341F2F666300F89830 /* filters_utils.c in Sources */, 80377D901F2F66A700F89830 /* lossless_msa.c in Sources */, 80377DA61F2F66A700F89830 /* yuv.c in Sources */, - 43CE757A1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, 3237F9E820161AE000A88143 /* NSImage+Compatibility.m in Sources */, 32C0FDE92013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 32F21B5920788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, @@ -4022,7 +3953,6 @@ 80377D831F2F66A700F89830 /* filters_msa.c in Sources */, 4A2CAE341AB4BB7500B6BC39 /* UIImageView+HighlightedWebCache.m in Sources */, 4A2CAE201AB4BB6C00B6BC39 /* SDImageCache.m in Sources */, - 43CE75801CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */, 4369C2801D9807EC007E863A /* UIView+WebCache.m in Sources */, 80377D8B1F2F66A700F89830 /* lossless_enc_neon.c in Sources */, 329A18611FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, @@ -4075,14 +4005,12 @@ 43C8929A1D9D6DD70022038D /* anim_decode.c in Sources */, 32F7C0752030114C00873181 /* SDImageTransformer.m in Sources */, 323F8B681F38EF770092B609 /* delta_palettization_enc.c in Sources */, - 43CE75D31CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */, 323F8B5C1F38EF770092B609 /* cost_enc.c in Sources */, 80377D001F2F66A100F89830 /* lossless_enc_msa.c in Sources */, 80377E891F2F66D000F89830 /* buffer_dec.c in Sources */, 80377C001F2F665300F89830 /* filters_utils.c in Sources */, 80377D061F2F66A100F89830 /* lossless_msa.c in Sources */, 80377D1C1F2F66A100F89830 /* yuv.c in Sources */, - 43CE75791CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, 80377CF71F2F66A100F89830 /* enc.c in Sources */, 3237F9EB20161AE000A88143 /* NSImage+Compatibility.m in Sources */, 32C0FDE72013426C001B8F2D /* SDWebImageIndicator.m in Sources */, @@ -4192,7 +4120,6 @@ 5D5B9145188EE8DD006D06BD /* NSData+ImageContentType.m in Sources */, 53EDFB8C17623F7C00698166 /* UIImage+MultiFormat.m in Sources */, ABBE71A818C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m in Sources */, - 43CE757F1CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */, 4369C27E1D9807EC007E863A /* UIView+WebCache.m in Sources */, 80377D011F2F66A100F89830 /* lossless_enc_neon.c in Sources */, 329A185F1FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, diff --git a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.h b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.h deleted file mode 100644 index c7153a55..00000000 --- a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * This file is part of the SDWebImage package. - * (c) Olivier Poitrey - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#import "SDWebImageCompat.h" - -#if SD_UIKIT - -#if __has_include() -#import -#else -#import "FLAnimatedImage.h" -#endif - -#import "SDWebImageManager.h" - -/** - * FLAnimatedImage is not a subclass of UIImage, so it's not possible to store it into the memory cache currently. However, for performance issue and cell reuse on FLAnimatedImageView, we use associate object to bind a FLAnimatedImage into UIImage when an animated GIF image load. For most cases, you don't need to touch this. - */ -@interface UIImage (FLAnimatedImage) - -/** - * The FLAnimatedImage associated to the UIImage instance when an animated GIF image load. - * For most cases this is read-only and you should avoid manually setting this value. Util some cases like using placeholder with a `FLAnimatedImage`. - */ -@property (nonatomic, strong, nullable) FLAnimatedImage *sd_FLAnimatedImage; - -@end - - -/** - * A category for the FLAnimatedImage imageView class that hooks it to the SDWebImage system. - * Very similar to the base class category (UIImageView (WebCache)) - */ -@interface FLAnimatedImageView (WebCache) - -/** - * Optimal frame cache size of FLAnimatedImage during initializer. (1.0.11 version later) - * This value will help you set `optimalFrameCacheSize` arg of FLAnimatedImage initializer after image load. - * Defaults to 0. - */ -@property (nonatomic, assign) NSUInteger sd_optimalFrameCacheSize; - -/** - * Predrawing control of FLAnimatedImage during initializer. (1.0.11 version later) - * This value will help you set `predrawingEnabled` arg of FLAnimatedImage initializer after image load. - * Defaults to YES. - */ -@property (nonatomic, assign) BOOL sd_predrawingEnabled; - -/** - * Cache control for associated FLAnimatedImage object for memory cache. When enabled, we will bind created FLAnimatedImage instance to UIImage, and store it into memory cache to avoid create this instance cause decoding performance. See `UIImage+FLAnimatedImage`. - * When enabled, this may consume more memory, if you are facing memory issue, disable it and let FLAnimatedImage been created just in time and dealloced as it not been used. However, when disabled, this may impact performance since we need query disk cache, create FLAnimatedImage and decoding even when the current GIF url is cached. - * Defatuls to YES; - */ -@property (nonatomic, assign) BOOL sd_cacheFLAnimatedImage; - -/** - * Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images - * The download is asynchronous and cached. - * - * @param url The url for the image. - */ -- (void)sd_setImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT; - -/** - * Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images - * The download is asynchronous and cached. - * Uses a placeholder until the request finishes. - * - * @param url The url for the image. - * @param placeholder The image to be set initially, until the image request finishes. - */ -- (void)sd_setImageWithURL:(nullable NSURL *)url - placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT; - -/** - * Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images - * The download is asynchronous and cached. - * Uses a placeholder until the request finishes. - * - * @param url The url for the image. - * @param placeholder The image to be set initially, until the image request finishes. - * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. - */ -- (void)sd_setImageWithURL:(nullable NSURL *)url - placeholderImage:(nullable UIImage *)placeholder - options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; - -/** - * Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images - * The download is asynchronous and cached. - * - * @param url The url for the image. - * @param completedBlock A block called when operation has been completed. This block has no return value - * and takes the requested UIImage as first parameter. In case of error the image parameter - * is nil and the second parameter may contain an NSError. The third parameter is a Boolean - * indicating if the image was retrieved from the local cache or from the network. - * The fourth parameter is the original image url. - */ -- (void)sd_setImageWithURL:(nullable NSURL *)url - completed:(nullable SDExternalCompletionBlock)completedBlock; - -/** - * Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images - * The download is asynchronous and cached. - * Uses a placeholder until the request finishes. - * - * @param url The url for the image. - * @param placeholder The image to be set initially, until the image request finishes. - * @param completedBlock A block called when operation has been completed. This block has no return value - * and takes the requested UIImage as first parameter. In case of error the image parameter - * is nil and the second parameter may contain an NSError. The third parameter is a Boolean - * indicating if the image was retrieved from the local cache or from the network. - * The fourth parameter is the original image url. - */ -- (void)sd_setImageWithURL:(nullable NSURL *)url - placeholderImage:(nullable UIImage *)placeholder - completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT; - -/** - * Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images - * The download is asynchronous and cached. - * Uses a placeholder until the request finishes. - * - * @param url The url for the image. - * @param placeholder The image to be set initially, until the image request finishes. - * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. - * @param completedBlock A block called when operation has been completed. This block has no return value - * and takes the requested UIImage as first parameter. In case of error the image parameter - * is nil and the second parameter may contain an NSError. The third parameter is a Boolean - * indicating if the image was retrieved from the local cache or from the network. - * The fourth parameter is the original image url. - */ -- (void)sd_setImageWithURL:(nullable NSURL *)url - placeholderImage:(nullable UIImage *)placeholder - options:(SDWebImageOptions)options - completed:(nullable SDExternalCompletionBlock)completedBlock; - -/** - * Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images - * The download is asynchronous and cached. - * Uses a placeholder until the request finishes. - * - * @param url The url for the image. - * @param placeholder The image to be set initially, until the image request finishes. - * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. - * @param progressBlock A block called while image is downloading - * @note the progress block is executed on a background queue - * @param completedBlock A block called when operation has been completed. This block has no return value - * and takes the requested UIImage as first parameter. In case of error the image parameter - * is nil and the second parameter may contain an NSError. The third parameter is a Boolean - * indicating if the image was retrieved from the local cache or from the network. - * The fourth parameter is the original image url. - */ -- (void)sd_setImageWithURL:(nullable NSURL *)url - placeholderImage:(nullable UIImage *)placeholder - options:(SDWebImageOptions)options - progress:(nullable SDImageLoaderProgressBlock)progressBlock - completed:(nullable SDExternalCompletionBlock)completedBlock; - -@end - -#endif diff --git a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m deleted file mode 100644 index 7ab7c55d..00000000 --- a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m +++ /dev/null @@ -1,175 +0,0 @@ -/* - * This file is part of the SDWebImage package. - * (c) Olivier Poitrey - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#import "FLAnimatedImageView+WebCache.h" - -#if SD_UIKIT -#import "objc/runtime.h" -#import "UIView+WebCacheOperation.h" -#import "UIView+WebCache.h" -#import "NSData+ImageContentType.h" -#import "UIImageView+WebCache.h" - -@implementation UIImage (FLAnimatedImage) - -- (FLAnimatedImage *)sd_FLAnimatedImage { - return objc_getAssociatedObject(self, @selector(sd_FLAnimatedImage)); -} - -- (void)setSd_FLAnimatedImage:(FLAnimatedImage *)sd_FLAnimatedImage { - objc_setAssociatedObject(self, @selector(sd_FLAnimatedImage), sd_FLAnimatedImage, OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -@end - -@implementation FLAnimatedImageView (WebCache) - -// These property based options will moved to `SDWebImageContext` in 5.x, to allow per-image-request level options instead of per-imageView-level options -- (NSUInteger)sd_optimalFrameCacheSize { - NSUInteger optimalFrameCacheSize = 0; - NSNumber *value = objc_getAssociatedObject(self, @selector(sd_optimalFrameCacheSize)); - if ([value isKindOfClass:[NSNumber class]]) { - optimalFrameCacheSize = value.unsignedShortValue; - } - return optimalFrameCacheSize; -} - -- (void)setSd_optimalFrameCacheSize:(NSUInteger)sd_optimalFrameCacheSize { - objc_setAssociatedObject(self, @selector(sd_optimalFrameCacheSize), @(sd_optimalFrameCacheSize), OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (BOOL)sd_predrawingEnabled { - BOOL predrawingEnabled = YES; - NSNumber *value = objc_getAssociatedObject(self, @selector(sd_predrawingEnabled)); - if ([value isKindOfClass:[NSNumber class]]) { - predrawingEnabled = value.boolValue; - } - return predrawingEnabled; -} - -- (void)setSd_predrawingEnabled:(BOOL)sd_predrawingEnabled { - objc_setAssociatedObject(self, @selector(sd_predrawingEnabled), @(sd_predrawingEnabled), OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (BOOL)sd_cacheFLAnimatedImage { - BOOL cacheFLAnimatedImage = YES; - NSNumber *value = objc_getAssociatedObject(self, @selector(sd_cacheFLAnimatedImage)); - if ([value isKindOfClass:[NSNumber class]]) { - cacheFLAnimatedImage = value.boolValue; - } - return cacheFLAnimatedImage; -} - -- (void)setSd_cacheFLAnimatedImage:(BOOL)sd_cacheFLAnimatedImage { - objc_setAssociatedObject(self, @selector(sd_cacheFLAnimatedImage), @(sd_cacheFLAnimatedImage), OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (void)sd_setImageWithURL:(nullable NSURL *)url { - [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil]; -} - -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder { - [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil]; -} - -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { - [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; -} - -- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { - [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; -} - -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { - [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock]; -} - -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { - [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; -} - -- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDExternalCompletionBlock)completedBlock { - [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; -} - -- (void)sd_setImageWithURL:(nullable NSURL *)url - placeholderImage:(nullable UIImage *)placeholder - options:(SDWebImageOptions)options - context:(nullable SDWebImageContext *)context - progress:(nullable SDImageLoaderProgressBlock)progressBlock - completed:(nullable SDExternalCompletionBlock)completedBlock { - dispatch_group_t group = dispatch_group_create(); - SDWebImageMutableContext *mutableContext; - if (context) { - mutableContext = [context mutableCopy]; - } else { - mutableContext = [NSMutableDictionary dictionary]; - } - mutableContext[SDWebImageContextSetImageGroup] = group; - __weak typeof(self)weakSelf = self; - [self sd_internalSetImageWithURL:url - placeholderImage:placeholder - options:options - context:mutableContext - setImageBlock:^(UIImage *image, NSData *imageData) { - // We could not directlly create the animated image on bacakground queue because it's time consuming, by the time we set it back, the current runloop has passed and the placeholder has been rendered and then replaced with animated image, this cause a flashing. - // Previously we use a trick to firstly set the static poster image, then set animated image back to avoid flashing, but this trick fail when using with custom UIView transition. Core Animation will use the current layer state to do rendering, so even we later set it back, the transition will not update. (it's recommended to use `SDWebImageTransition` instead) - // So we have no choice to force store the FLAnimatedImage into memory cache using a associated object binding to UIImage instance. This consumed memory is adoptable and much smaller than `_UIAnimatedImage` for big GIF - FLAnimatedImage *associatedAnimatedImage = image.sd_FLAnimatedImage; - if (associatedAnimatedImage) { - // Asscociated animated image exist - weakSelf.animatedImage = associatedAnimatedImage; - weakSelf.image = nil; - if (group) { - dispatch_group_leave(group); - } - } else if ([NSData sd_imageFormatForImageData:imageData] == SDImageFormatGIF) { - // Firstly set the static poster image to avoid flashing - UIImage *posterImage = image.images ? image.images.firstObject : image; - weakSelf.image = posterImage; - weakSelf.animatedImage = nil; - // Secondly create FLAnimatedImage in global queue because it's time consuming, then set it back - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - FLAnimatedImage *animatedImage; - // Compatibility in 4.x for lower version FLAnimatedImage. - if ([FLAnimatedImage respondsToSelector:@selector(initWithAnimatedGIFData:optimalFrameCacheSize:predrawingEnabled:)]) { - animatedImage = [[FLAnimatedImage alloc] initWithAnimatedGIFData:imageData optimalFrameCacheSize:weakSelf.sd_optimalFrameCacheSize predrawingEnabled:weakSelf.sd_predrawingEnabled]; - } else { - animatedImage = [[FLAnimatedImage alloc] initWithAnimatedGIFData:imageData]; - } - dispatch_async(dispatch_get_main_queue(), ^{ - if (weakSelf.sd_cacheFLAnimatedImage) { - image.sd_FLAnimatedImage = animatedImage; - } - weakSelf.animatedImage = animatedImage; - weakSelf.image = nil; - if (group) { - dispatch_group_leave(group); - } - }); - }); - } else { - // Not animated image - weakSelf.image = image; - weakSelf.animatedImage = nil; - if (group) { - dispatch_group_leave(group); - } - } - } - progress:progressBlock - completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { - if (completedBlock) { - completedBlock(image, error, cacheType, imageURL); - } - }]; -} - -@end - -#endif diff --git a/SDWebImage/SDImageCodersManager.h b/SDWebImage/SDImageCodersManager.h index 0e3b20db..e64c4c20 100644 --- a/SDWebImage/SDImageCodersManager.h +++ b/SDWebImage/SDImageCodersManager.h @@ -17,7 +17,7 @@ Note: the `coders` getter will return the coders in their reversed order Example: - - by default we internally set coders = `IOCoder`, `WebPCoder`. (`GIFCoder` is not recommended to add only if you want to get GIF support without `FLAnimatedImage`) + - by default we internally set coders = `IOCoder`, `GIFCoder`, `APNGCoder` and `WebPCoder` (When WebP subspec is available). - calling `coders` will return `@[WebPCoder, IOCoder]` - call `[addCoder:[MyCrazyCoder new]]` - calling `coders` now returns `@[MyCrazyCoder, WebPCoder, IOCoder]` diff --git a/SDWebImage/SDImageIOCoder.h b/SDWebImage/SDImageIOCoder.h index 634eb7bb..98682ed6 100644 --- a/SDWebImage/SDImageIOCoder.h +++ b/SDWebImage/SDImageIOCoder.h @@ -14,7 +14,7 @@ GIF Also supports static GIF (meaning will only handle the 1st frame). - For a full GIF support, we recommend `FLAnimatedImage` or our less performant `SDImageGIFCoder` + For a full GIF support, we recommend `SDAnimatedImageView` to keep both CPU and memory balanced. HEIC This coder also supports HEIC format because ImageIO supports it natively. But it depends on the system capabilities, so it won't work on all devices, see: https://devstreaming-cdn.apple.com/videos/wwdc/2017/511tj33587vdhds/511/511_working_with_heif_and_hevc.pdf diff --git a/Tests/Podfile b/Tests/Podfile index 9bb1ac31..ac090843 100644 --- a/Tests/Podfile +++ b/Tests/Podfile @@ -11,7 +11,6 @@ target 'Tests' do pod 'KVOController' pod 'SDWebImage/WebP', :path => '../' pod 'SDWebImage/MapKit', :path => '../' - pod 'SDWebImage/GIF', :path => '../' end diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index cd1d1492..b3185412 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -362,7 +362,7 @@ "${SRCROOT}/Pods/Target Support Files/Pods-Tests Mac/Pods-Tests Mac-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Expecta-macOS/Expecta.framework", "${BUILT_PRODUCTS_DIR}/KVOController-macOS/KVOController.framework", - "${BUILT_PRODUCTS_DIR}/SDWebImage-Core-MapKit-WebP/SDWebImage.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImage-macOS/SDWebImage.framework", "${BUILT_PRODUCTS_DIR}/libwebp-macOS/libwebp.framework", ); name = "[CP] Embed Pods Frameworks"; @@ -436,15 +436,13 @@ inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Expecta-iOS/Expecta.framework", - "${BUILT_PRODUCTS_DIR}/FLAnimatedImage/FLAnimatedImage.framework", "${BUILT_PRODUCTS_DIR}/KVOController-iOS/KVOController.framework", - "${BUILT_PRODUCTS_DIR}/SDWebImage-Core-GIF-MapKit-WebP/SDWebImage.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImage-iOS/SDWebImage.framework", "${BUILT_PRODUCTS_DIR}/libwebp-iOS/libwebp.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Expecta.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FLAnimatedImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KVOController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", diff --git a/Tests/Tests/SDImageCoderTests.m b/Tests/Tests/SDImageCoderTests.m index ea2907d9..84995795 100644 --- a/Tests/Tests/SDImageCoderTests.m +++ b/Tests/Tests/SDImageCoderTests.m @@ -100,7 +100,7 @@ isAnimatedImage:YES]; } -- (void)test20ThatOurGIFCoderWorksNotFLAnimatedImage { +- (void)test20ThatOurGIFCoderWorks { NSURL *gifURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImage" withExtension:@"gif"]; [self verifyCoder:[SDImageGIFCoder sharedCoder] withLocalImageURL:gifURL diff --git a/Tests/Tests/SDWebCacheCategoriesTests.m b/Tests/Tests/SDWebCacheCategoriesTests.m index 6e988d0e..74e0c3b2 100644 --- a/Tests/Tests/SDWebCacheCategoriesTests.m +++ b/Tests/Tests/SDWebCacheCategoriesTests.m @@ -118,25 +118,6 @@ [self waitForExpectationsWithCommonTimeout]; } -- (void)testFLAnimatedImageViewSetImageWithURL { - XCTestExpectation *expectation = [self expectationWithDescription:@"FLAnimatedImageView setImageWithURL"]; - - FLAnimatedImageView *imageView = [[FLAnimatedImageView alloc] init]; - NSURL *originalImageURL = [NSURL URLWithString:@"https://www.interntheory.com/img/loading-small.gif"]; - - [imageView sd_setImageWithURL:originalImageURL - completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { - expect(image).toNot.beNil(); - expect(error).to.beNil(); - expect(originalImageURL).to.equal(imageURL); - - expect(imageView.animatedImage).toNot.beNil(); - [expectation fulfill]; - }]; - [self waitForExpectationsWithCommonTimeout]; -} -#endif - - (void)testUIViewImageProgressKVOWork { XCTestExpectation *expectation = [self expectationWithDescription:@"UIView imageProgressKVO failed"]; UIView *view = [[UIView alloc] init]; diff --git a/Vendors/FLAnimatedImage b/Vendors/FLAnimatedImage deleted file mode 160000 index 25307796..00000000 --- a/Vendors/FLAnimatedImage +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 25307796cfcf66cb5b98774e050e93f64e0f2cde diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index 9a2d5771..e38da0a2 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -81,12 +81,6 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #endif - -// GIF -#if __has_include() -#import -#endif - // WebP #if __has_include() #import From 2299d9ab6ab7ac9bf7c40c6c06f389e0b2e8dfac Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Mon, 16 Jul 2018 10:13:19 +0300 Subject: [PATCH 209/361] Another update per @dreampiggy --- Docs/SDWebImage-5.0-Migration-guide.md | 52 ++++++++++++++------------ 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/Docs/SDWebImage-5.0-Migration-guide.md b/Docs/SDWebImage-5.0-Migration-guide.md index 7253f5a4..9fe221fd 100644 --- a/Docs/SDWebImage-5.0-Migration-guide.md +++ b/Docs/SDWebImage-5.0-Migration-guide.md @@ -28,9 +28,9 @@ Swift: imageView.sd_setImage(with: url, placeholderImage: placeholder) ``` -However, all view categories in 5.0 introduce a new extra arg called `SDWebImageContext`. Which can hold anything that previous enum `SDWebImageOptions` can not. This allow user to control advanced behavior for view loading as well as many aspect. See the declaration for `SDWebImageContext` for detailed information. +However, all view categories in 5.0 introduce a new extra arg called `SDWebImageContext`. Which can hold anything that previous enum `SDWebImageOptions` can not. This allow user to control advanced behavior for image loading as well as many aspect (cache, loader, etc). See the declaration for `SDWebImageContext` for detailed information. -### New Features +### New Feature #### Animated Image View @@ -44,7 +44,10 @@ In 5.0, we introduce a easy way to provide a image transform process after the i #### Customization -In 5.0, we refactor our framework architecture, to allow it easy to customize for advanced user, without breaking anything or create their fork. We introduce [Custom Cache](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-cache-50), [Custom Loader](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-loader-50), and make current [Custom Coder](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-coder-420) works better for these developers. +In 5.0, we refactor our framework architecture with many aspect. This make our framework easier to customize for advanced user, without hook anything or create their fork. We introduce [Custom Cache](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-cache-50) to control detailed cache loading behavior, and separate the memory cache & disk cache implementation. We introduce [Custom Loader](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-loader-50) to allow custom loading from your own source (which even not need to be on network). And also, we change current [Custom Coder](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-coder-420) to works better for custom image decoder/encoder and animated image. + +#### View Indicator +In 5.0, we refactor the current image loading indicator API. To use a better and extensible API for both iOS/tvOS/macOS. Which is suitable for easy usage for provide a loading view during the image loading process. See [View Indicator](https://github.com/rs/SDWebImage/wiki/How-to-use#use-view-indicator-50) for more detailed information. #### FLAnimatedImage support moved to a dedicated plugin repo @@ -96,11 +99,11 @@ By taking the advantage of [Custom Loader](https://github.com/rs/SDWebImage/wiki - `sd_internalSetImageWithURL:placeholderImage:options:operationKey:setImageBlock:progress:completed:` renamed to `UIView sd_internalSetImageWithURL:placeholderImage:options:context:setImageBlock:progress:completed:` (The biggest changes is that the completion block type from `SDExternalCompletionBlock` to `SDInternalCompletionBlock`. Which allow advanced user to get more information of image loading process) - `sd_internalSetImageWithURL:placeholderImage:options:operationKey:setImageBlock:progress:completed:context:` removed - activity indicator refactoring - use `sd_imageIndicator` with `SDWebImageActivityIndicator` -- `sd_setShowActivityIndicatorView:` removed -- `sd_setIndicatorStyle:` removed -- `sd_showActivityIndicatorView` removed -- `sd_addActivityIndicator:` removed -- `sd_removeActivityIndicator:` removed + - `sd_setShowActivityIndicatorView:` removed + - `sd_setIndicatorStyle:` removed + - `sd_showActivityIndicatorView` removed + - `sd_addActivityIndicator:` removed + - `sd_removeActivityIndicator:` removed #### UIImage @@ -161,53 +164,56 @@ By taking the advantage of [Custom Loader](https://github.com/rs/SDWebImage/wiki - `SDWebImageInternalSetImageGroupKey` renamed to `SDWebImageContextSetImageGroup` - `SDWebImageExternalCustomManagerKey` renamed to `SDWebImageContextCustomManager` -### Swift Specific API Changes -We did a full cleanup of the Swift APIs. We are using many modern Objective-C declarations to generate the Swift API. We now provide full nullability support, string enum, class property, and even custom Swift API name, all to make the framework easier to use for our Swift users. Here are the API change specify for Swift. +#### Swift Specific API Change +In SDWebImage 5.0 we did a clean up of the API. We are using many modern Objective-C declarations to generate the Swift API. We now provide full nullability support, string enum, class property, and even custom Swift API name, all to make the framework easier to use for our Swift users. Here are the API change specify for Swift. -#### UIView+WebCache +##### UIView+WebCache - `sd_imageURL()` changed to `sd_imageURL` -#### SDWebImageManager +##### SDImageCache +- `shared()` changed to `shared` + +##### SDWebImageManager - `shared()` changed to `shared` - `isRunning()` changed to `isRunning` -#### SDWebImageDownloader +##### SDWebImageDownloader - `shared()` changed to `shared` - `setOperationClass(_:)` available for Swift user with `operationClass` property - `setSuspended(_:)` changed to `isSuspended` property -#### SDWebImageDownloadOperation +##### SDWebImageDownloadOperation - `SDWebImageDownloadOperationInterface` protocol renamed to `SDWebImageDownloadOperationProtocol`. -#### SDImageCodersManager +##### SDImageCodersManager - `sharedInstance()` changed to `shared` -#### SDImageIOCoder +##### SDImageIOCoder - `shared()` changed to `shared` -#### SDImageGIFCoder +##### SDImageGIFCoder - `shared()` changed to `shared` -#### SDImageWebPCoder +##### SDImageWebPCoder - `shared()` changed to `shared` -#### NSData-ImageContentType +##### NSData-ImageContentType - `sd_UTTypeFromSDImageFormat` return `CFString` instead of `Unmanaged` -#### UIButton-WebCache +##### UIButton-WebCache - `sd_currentImageURL()` changed to `sd_currentImageURL` - -#### NSButton-WebCache + +##### NSButton-WebCache - `sd_currentImageURL()` changed to `sd_currentImageURL` - `sd_currentAlternateImageURL()` changed to `sd_currentAlternateImageURL` ### Full API Diff -For advanced user who need the detailed API diff, we provide the full diff in a HTML web page: [SDWebImage 5.0 API Diff](API-Diff/5.0/apidiff.html) +For advanced user who need the detailed API diff, we provide the full diff in a HTML web page: [SDWebImage 5.0 API Diff](https://raw.githubusercontent.com/rs/SDWebImage/master/Docs/Diff/5.0/apidiff.html) From a42577ce5d82b6a07644b56b141f797661979b10 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Mon, 16 Jul 2018 10:31:52 +0300 Subject: [PATCH 210/361] Trying to make some descriptions more clear --- Docs/SDWebImage-5.0-Migration-guide.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Docs/SDWebImage-5.0-Migration-guide.md b/Docs/SDWebImage-5.0-Migration-guide.md index 9fe221fd..cac95da0 100644 --- a/Docs/SDWebImage-5.0-Migration-guide.md +++ b/Docs/SDWebImage-5.0-Migration-guide.md @@ -28,34 +28,34 @@ Swift: imageView.sd_setImage(with: url, placeholderImage: placeholder) ``` -However, all view categories in 5.0 introduce a new extra arg called `SDWebImageContext`. Which can hold anything that previous enum `SDWebImageOptions` can not. This allow user to control advanced behavior for image loading as well as many aspect (cache, loader, etc). See the declaration for `SDWebImageContext` for detailed information. +However, all view categories in 5.0 introduce a new extra arg called `SDWebImageContext`. This param can hold anything, as oposed to the previous `SDWebImageOptions` enum limitations. This gives developers advanced control for the behavior of image loading (cache, loader, etc). See the declaration for `SDWebImageContext` for detailed information. ### New Feature #### Animated Image View -In 5.0, we introduce a brand new animated image solution. Which including animated image loading, rendering, decoding, and also support customization for advanced user. +In 5.0, we introduced a brand new mechanism for supporting animated images. This includes animated image loading, rendering, decoding, and also supports customizations (for advanced users). -This animated image solution is available for iOS/tvOS/macOS. The `SDAnimatedImage` is subclass of `UIImage/NSImage`, and `SDAnimatedImageView` is subclass of `UIImageView/NSImageView`, to allow most compatible for common framework APIs. See [Animated Image](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#animated-image-50) for more detailed information. +This animated image solution is available for `iOS`/`tvOS`/`macOS`. The `SDAnimatedImage` is subclass of `UIImage/NSImage`, and `SDAnimatedImageView` is subclass of `UIImageView/NSImageView`, to make them compatible with the common frameworks APIs. See [Animated Image](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#animated-image-50) for more detailed information. #### Transformer -In 5.0, we introduce a easy way to provide a image transform process after the image was downloaded from network. Which allow user to easily scale, rotate, rounded corner the original image. And even support chain a list of transformers together to output the final one. These transformed image will also stored to cache to avoid duplicate process. See [Image Transformer](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#transformer-50) for more detailed information. +In 5.0, we introduced an easy way to hook an image transformation process after the image was downloaded from network. This allows the user to easily scale, rotate, add rounded corner the original image and even chain a list of transformations. These transformed images will also be stored to the cache as they are after transformation. The reasons for this decision are: avoiding redoing the transformations (which can lead to unwanted behavior) and also time saving. See [Image Transformer](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#transformer-50) for more detailed information. #### Customization -In 5.0, we refactor our framework architecture with many aspect. This make our framework easier to customize for advanced user, without hook anything or create their fork. We introduce [Custom Cache](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-cache-50) to control detailed cache loading behavior, and separate the memory cache & disk cache implementation. We introduce [Custom Loader](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-loader-50) to allow custom loading from your own source (which even not need to be on network). And also, we change current [Custom Coder](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-coder-420) to works better for custom image decoder/encoder and animated image. +In 5.0, we refactored our framework architecture in many aspects. This makes our framework easier to customize for advanced users, without the need for hooking anything or forking. We introduced [Custom Cache](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-cache-50) to control detailed cache loading behavior, and separate the memory cache & disk cache implementation. We introduced [Custom Loader](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-loader-50) to allow custom loading from your own source (doesn't have to be the network). And also, we changed the current [Custom Coder](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-coder-420) to work better for custom image decoder/encoder and animated images. #### View Indicator -In 5.0, we refactor the current image loading indicator API. To use a better and extensible API for both iOS/tvOS/macOS. Which is suitable for easy usage for provide a loading view during the image loading process. See [View Indicator](https://github.com/rs/SDWebImage/wiki/How-to-use#use-view-indicator-50) for more detailed information. +In 5.0, we refactored the image loading indicator API into a better and extensible API for `iOS`/`tvOS`/`macOS`. This is suitable for easy usage like providing a loading view during the image loading process. See [View Indicator](https://github.com/rs/SDWebImage/wiki/How-to-use#use-view-indicator-50) for more detailed information. #### FLAnimatedImage support moved to a dedicated plugin repo -Since we introduce the new animated image solution. Now we are no longer hosting the integration with `FLAnimatedImage` inside this repo. But for user who need `FLAnimatedImage` support. We have a dedicated repo for that and contains all the code compatible for SDWebImage 5.0. See [SDWebImageFLPlugin](https://github.com/SDWebImage/SDWebImageFLPlugin) for more detailed information. +In order to clean up things and make our core project do less things, we decided that the `FLAnimatedImage` integration does not belong here. From 5.0, this will still be available, but under a dedicated repo [SDWebImageFLPlugin](https://github.com/SDWebImage/SDWebImageFLPlugin). #### Photos Plugin -By taking the advantage of [Custom Loader](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-loader-50) feature, we introduce a plugin to allow easily load Photos Library images. See [SDWebImagePhotosPlugin](https://github.com/SDWebImage/SDWebImagePhotosPlugin) for more detailed information. +By taking the advantage of the [Custom Loader](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-loader-50) feature, we introduced a plugin to allow easy loading images from the Photos Library. See [SDWebImagePhotosPlugin](https://github.com/SDWebImage/SDWebImagePhotosPlugin) for more detailed information. ### API Changes From c797279e70282ae2ee33b8fab934018e9996f731 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Mon, 16 Jul 2018 10:46:08 +0300 Subject: [PATCH 211/361] Accidentally removed `endif` - added back --- Tests/Tests/SDWebCacheCategoriesTests.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/Tests/SDWebCacheCategoriesTests.m b/Tests/Tests/SDWebCacheCategoriesTests.m index 74e0c3b2..eedca13b 100644 --- a/Tests/Tests/SDWebCacheCategoriesTests.m +++ b/Tests/Tests/SDWebCacheCategoriesTests.m @@ -117,6 +117,7 @@ }]; [self waitForExpectationsWithCommonTimeout]; } +#endif - (void)testUIViewImageProgressKVOWork { XCTestExpectation *expectation = [self expectationWithDescription:@"UIView imageProgressKVO failed"]; From 49cd121b05a7598a75326f09c7d33dd3bf6b768a Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Tue, 17 Jul 2018 10:56:42 +0300 Subject: [PATCH 212/361] CocoaPods 1.5.0 for the Tests project --- .../project.pbxproj | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index b3185412..51eda380 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -255,7 +255,6 @@ 32B99E8F203B2DF90017FD66 /* Frameworks */, 32B99E90203B2DF90017FD66 /* Resources */, 051A05AAEF597E2716FD5814 /* [CP] Embed Pods Frameworks */, - E24640E4B238C940135CC3B6 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -275,7 +274,6 @@ DA248D50195472AA00390AB0 /* Frameworks */, DA248D51195472AA00390AB0 /* Resources */, C86216497B5A0BA9501E2C07 /* [CP] Embed Pods Frameworks */, - 85E5D3885A03BFC23B050908 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -395,21 +393,6 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 85E5D3885A03BFC23B050908 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; C584EBF185E2BBD234CD3350 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -452,21 +435,6 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - E24640E4B238C940135CC3B6 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests Mac/Pods-Tests Mac-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ From 13f293d951f4f6c3636d7fadfbe290ff3641c424 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Tue, 17 Jul 2018 10:56:58 +0300 Subject: [PATCH 213/361] Bumped Copyright to cover 2018 --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 92a252a9..93321c73 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2009-2017 Olivier Poitrey rs@dailymotion.com +Copyright (c) 2009-2018 Olivier Poitrey rs@dailymotion.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From c90c13e43397a8b36553c141224b8295d879bf59 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Tue, 17 Jul 2018 11:08:37 +0300 Subject: [PATCH 214/361] Updated README and CHANGELOG --- CHANGELOG.md | 4 +--- README.md | 17 +++++++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 365f4c13..a4b265de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## [5.0.0 - Release_name_TBD, on Apr xxth, 2018](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta) +## [5.0.0-beta - Customizable SDWebImage, on Jul 17th, 2018](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta) See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/milestone/15) #### Infrastructure @@ -50,8 +50,6 @@ See the [5.0 Migration Guide](Docs/SDWebImage-5.0-Migration-guide.md) for a list #### Fixes - `SDWebImageManager loadImageWithURL:options:progress:completed:` changed the `completed` param requirement from `nullable` to `nonnull` #2164 -TODO: Update diagrams - ## [4.4.1 - 4.4 patch, on June 7th, 2018](https://github.com/rs/SDWebImage/releases/tag/4.4.1) See [all tickets marked for the 4.4.1 release](https://github.com/rs/SDWebImage/milestone/26) diff --git a/README.md b/README.md index 3e48b593..725ad2dc 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,11 @@ This library provides an async image downloader with cache support. For convenie - [x] An asynchronous image downloader - [x] An asynchronous memory + disk image caching with automatic cache expiration handling - [x] A background image decompression +- [x] Improved [support for animated images](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#animated-image-50) +- [x] [Customizable and composable transformations](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#transformer-50) can be applied to the images right after download +- [x] [Custom cache control](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-cache-50) +- [x] Expand the image loading capabilites by adding your [own custom loaders](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-loader-50) or using prebuilt loaders like [FLAnimatedImage plugin](https://github.com/SDWebImage/SDWebImageFLPlugin) or [Photos Library plugin](https://github.com/SDWebImage/SDWebImagePhotosPlugin) +- [x] [Loading indicators](https://github.com/rs/SDWebImage/wiki/How-to-use#use-view-indicator-50) - [x] A guarantee that the same URL won't be downloaded several times - [x] A guarantee that bogus URLs won't be retried again and again - [x] A guarantee that main thread will never be blocked @@ -92,11 +97,11 @@ imageView.sd_setImage(with: URL(string: "http://www.domain.com/path/to/image.jpg ## Animated Images (GIF) support -- Starting with the 4.0 version, we rely on [FLAnimatedImage](https://github.com/Flipboard/FLAnimatedImage) to take care of our animated images. -- If you use cocoapods, add `pod 'SDWebImage/GIF'` to your podfile. -- To use it, simply make sure you use `FLAnimatedImageView` instead of `UIImageView`. -- **Note**: there is a backwards compatible feature, so if you are still trying to load a GIF into a `UIImageView`, it will only show the 1st frame as a static image by default. However, you can enable the full GIF support by using the built-in GIF coder. See [GIF coder](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#gif-coder) -- **Important**: FLAnimatedImage only works on the iOS platform. For macOS, use `NSImageView` with `animates` set to `YES` to show the entire animated images and `NO` to only show the 1st frame. For all the other platforms (tvOS, watchOS) we will fallback to the backwards compatibility feature described above +In 5.0, we introduced a brand new mechanism for supporting animated images. This includes animated image loading, rendering, decoding, and also supports customizations (for advanced users). +This animated image solution is available for `iOS`/`tvOS`/`macOS`. The `SDAnimatedImage` is subclass of `UIImage/NSImage`, and `SDAnimatedImageView` is subclass of `UIImageView/NSImageView`, to make them compatible with the common frameworks APIs. See [Animated Image](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#animated-image-50) for more detailed information. + +#### FLAnimatedImage integration has its own dedicated repo +In order to clean up things and make our core project do less things, we decided that the `FLAnimatedImage` integration does not belong here. From 5.0, this will still be available, but under a dedicated repo [SDWebImageFLPlugin](https://github.com/SDWebImage/SDWebImageFLPlugin). ## Installation @@ -123,7 +128,7 @@ use_frameworks! #### Subspecs -There are 4 subspecs available now: `Core`, `MapKit`, `GIF` and `WebP` (this means you can install only some of the SDWebImage modules. By default, you get just `Core`, so if you need `WebP`, you need to specify it). +There are 3 subspecs available now: `Core`, `MapKit` and `WebP` (this means you can install only some of the SDWebImage modules. By default, you get just `Core`, so if you need `WebP`, you need to specify it). Podfile example: ``` From 820f13ec935ae6510cbb5471dd621ea5fe931ca8 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Tue, 17 Jul 2018 17:51:23 +0800 Subject: [PATCH 215/361] Fix nullable key when get image load operation --- SDWebImage/UIView+WebCacheOperation.m | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/SDWebImage/UIView+WebCacheOperation.m b/SDWebImage/UIView+WebCacheOperation.m index d83c8e0c..5be2b03e 100644 --- a/SDWebImage/UIView+WebCacheOperation.m +++ b/SDWebImage/UIView+WebCacheOperation.m @@ -31,9 +31,11 @@ typedef NSMapTable> SDOperationsDictionary; - (nullable id)sd_imageLoadOperationForKey:(nullable NSString *)key { id operation; - SDOperationsDictionary *operationDictionary = [self sd_operationDictionary]; - @synchronized (self) { - operation = [operationDictionary objectForKey:key]; + if (key) { + SDOperationsDictionary *operationDictionary = [self sd_operationDictionary]; + @synchronized (self) { + operation = [operationDictionary objectForKey:key]; + } } return operation; } From b291351754141f5f125377c6349ef814170f9373 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 18 Jul 2018 16:40:33 +0800 Subject: [PATCH 216/361] Replace __bridge_transfer with __bridge when convert from CFStringRef to NSString --- SDWebImage/SDImageAPNGCoder.m | 20 ++++++++++---------- SDWebImage/SDImageCoderHelper.m | 2 +- SDWebImage/SDImageGIFCoder.m | 16 ++++++++-------- SDWebImage/SDImageIOCoder.m | 4 ++-- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/SDWebImage/SDImageAPNGCoder.m b/SDWebImage/SDImageAPNGCoder.m index 5dafa197..97f54876 100644 --- a/SDWebImage/SDImageAPNGCoder.m +++ b/SDWebImage/SDImageAPNGCoder.m @@ -139,9 +139,9 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef - (NSUInteger)sd_imageLoopCountWithSource:(CGImageSourceRef)source { NSUInteger loopCount = 0; NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(source, nil); - NSDictionary *pngProperties = [imageProperties valueForKey:(__bridge_transfer NSString *)kCGImagePropertyPNGDictionary]; + NSDictionary *pngProperties = [imageProperties valueForKey:(__bridge NSString *)kCGImagePropertyPNGDictionary]; if (pngProperties) { - NSNumber *apngLoopCount = [pngProperties valueForKey:(__bridge_transfer NSString *)kCGImagePropertyAPNGLoopCount]; + NSNumber *apngLoopCount = [pngProperties valueForKey:(__bridge NSString *)kCGImagePropertyAPNGLoopCount]; if (apngLoopCount != nil) { loopCount = apngLoopCount.unsignedIntegerValue; } @@ -155,11 +155,11 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties; NSDictionary *pngProperties = frameProperties[(NSString *)kCGImagePropertyPNGDictionary]; - NSNumber *delayTimeUnclampedProp = pngProperties[(__bridge_transfer NSString *)kCGImagePropertyAPNGUnclampedDelayTime]; + NSNumber *delayTimeUnclampedProp = pngProperties[(__bridge NSString *)kCGImagePropertyAPNGUnclampedDelayTime]; if (delayTimeUnclampedProp != nil) { frameDuration = [delayTimeUnclampedProp floatValue]; } else { - NSNumber *delayTimeProp = pngProperties[(__bridge_transfer NSString *)kCGImagePropertyAPNGDelayTime]; + NSNumber *delayTimeProp = pngProperties[(__bridge NSString *)kCGImagePropertyAPNGDelayTime]; if (delayTimeProp != nil) { frameDuration = [delayTimeProp floatValue]; } @@ -202,7 +202,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef if ([options valueForKey:SDImageCoderEncodeCompressionQuality]) { compressionQuality = [[options valueForKey:SDImageCoderEncodeCompressionQuality] doubleValue]; } - [properties setValue:@(compressionQuality) forKey:(__bridge_transfer NSString *)kCGImageDestinationLossyCompressionQuality]; + [properties setValue:@(compressionQuality) forKey:(__bridge NSString *)kCGImageDestinationLossyCompressionQuality]; BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; if (encodeFirstFrame || frames.count == 0) { @@ -211,15 +211,15 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef } else { // for animated APNG images NSUInteger loopCount = image.sd_imageLoopCount; - NSDictionary *pngProperties = @{(__bridge_transfer NSString *)kCGImagePropertyAPNGLoopCount : @(loopCount)}; - [properties setValue:pngProperties forKey:(__bridge_transfer NSString *)kCGImagePropertyPNGDictionary]; + NSDictionary *pngProperties = @{(__bridge NSString *)kCGImagePropertyAPNGLoopCount : @(loopCount)}; + [properties setValue:pngProperties forKey:(__bridge NSString *)kCGImagePropertyPNGDictionary]; CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)properties); for (size_t i = 0; i < frames.count; i++) { SDImageFrame *frame = frames[i]; float frameDuration = frame.duration; CGImageRef frameImageRef = frame.image.CGImage; - NSDictionary *frameProperties = @{(__bridge_transfer NSString *)kCGImagePropertyPNGDictionary : @{(__bridge_transfer NSString *)kCGImagePropertyAPNGDelayTime : @(frameDuration)}}; + NSDictionary *frameProperties = @{(__bridge NSString *)kCGImagePropertyPNGDictionary : @{(__bridge NSString *)kCGImagePropertyAPNGDelayTime : @(frameDuration)}}; CGImageDestinationAddImage(imageDestination, frameImageRef, (__bridge CFDictionaryRef)frameProperties); } } @@ -244,7 +244,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef self = [super init]; if (self) { CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatPNG]; - _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceTypeIdentifierHint : (__bridge_transfer NSString *)imageUTType}); + _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceTypeIdentifierHint : (__bridge NSString *)imageUTType}); CGFloat scale = 1; if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; @@ -323,7 +323,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef self = [super init]; if (self) { // use Image/IO cache because it's already keep a balance between CPU & memory - CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)}); + CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceShouldCache : @(YES)}); if (!imageSource) { return nil; } diff --git a/SDWebImage/SDImageCoderHelper.m b/SDWebImage/SDImageCoderHelper.m index a08abf68..713620a4 100644 --- a/SDWebImage/SDImageCoderHelper.m +++ b/SDWebImage/SDImageCoderHelper.m @@ -92,7 +92,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over SDImageFrame *frame = frames[i]; float frameDuration = frame.duration; CGImageRef frameImageRef = frame.image.CGImage; - NSDictionary *frameProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary : @{(__bridge_transfer NSString *)kCGImagePropertyGIFDelayTime : @(frameDuration)}}; + NSDictionary *frameProperties = @{(__bridge NSString *)kCGImagePropertyGIFDictionary : @{(__bridge NSString *)kCGImagePropertyGIFDelayTime : @(frameDuration)}}; CGImageDestinationAddImage(imageDestination, frameImageRef, (__bridge CFDictionaryRef)frameProperties); } } diff --git a/SDWebImage/SDImageGIFCoder.m b/SDWebImage/SDImageGIFCoder.m index b5f68dd0..bf782bb4 100644 --- a/SDWebImage/SDImageGIFCoder.m +++ b/SDWebImage/SDImageGIFCoder.m @@ -132,9 +132,9 @@ - (NSUInteger)sd_imageLoopCountWithSource:(CGImageSourceRef)source { NSUInteger loopCount = 1; NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(source, nil); - NSDictionary *gifProperties = [imageProperties valueForKey:(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary]; + NSDictionary *gifProperties = [imageProperties valueForKey:(__bridge NSString *)kCGImagePropertyGIFDictionary]; if (gifProperties) { - NSNumber *gifLoopCount = [gifProperties valueForKey:(__bridge_transfer NSString *)kCGImagePropertyGIFLoopCount]; + NSNumber *gifLoopCount = [gifProperties valueForKey:(__bridge NSString *)kCGImagePropertyGIFLoopCount]; if (gifLoopCount != nil) { loopCount = gifLoopCount.unsignedIntegerValue; } @@ -184,7 +184,7 @@ self = [super init]; if (self) { CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatGIF]; - _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceTypeIdentifierHint : (__bridge_transfer NSString *)imageUTType}); + _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceTypeIdentifierHint : (__bridge NSString *)imageUTType}); CGFloat scale = 1; if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; @@ -284,7 +284,7 @@ if ([options valueForKey:SDImageCoderEncodeCompressionQuality]) { compressionQuality = [[options valueForKey:SDImageCoderEncodeCompressionQuality] doubleValue]; } - [properties setValue:@(compressionQuality) forKey:(__bridge_transfer NSString *)kCGImageDestinationLossyCompressionQuality]; + [properties setValue:@(compressionQuality) forKey:(__bridge NSString *)kCGImageDestinationLossyCompressionQuality]; BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; if (encodeFirstFrame || frames.count == 0) { @@ -293,15 +293,15 @@ } else { // for animated GIF images NSUInteger loopCount = image.sd_imageLoopCount; - NSDictionary *gifProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFLoopCount : @(loopCount)}; - [properties setValue:gifProperties forKey:(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary]; + NSDictionary *gifProperties = @{(__bridge NSString *)kCGImagePropertyGIFLoopCount : @(loopCount)}; + [properties setValue:gifProperties forKey:(__bridge NSString *)kCGImagePropertyGIFDictionary]; CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)properties); for (size_t i = 0; i < frames.count; i++) { SDImageFrame *frame = frames[i]; float frameDuration = frame.duration; CGImageRef frameImageRef = frame.image.CGImage; - NSDictionary *frameProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary : @{(__bridge_transfer NSString *)kCGImagePropertyGIFDelayTime : @(frameDuration)}}; + NSDictionary *frameProperties = @{(__bridge NSString *)kCGImagePropertyGIFDictionary : @{(__bridge NSString *)kCGImagePropertyGIFDelayTime : @(frameDuration)}}; CGImageDestinationAddImage(imageDestination, frameImageRef, (__bridge CFDictionaryRef)frameProperties); } } @@ -324,7 +324,7 @@ self = [super init]; if (self) { // use Image/IO cache because it's already keep a balance between CPU & memory - CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)}); + CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceShouldCache : @(YES)}); if (!imageSource) { return nil; } diff --git a/SDWebImage/SDImageIOCoder.m b/SDWebImage/SDImageIOCoder.m index 4701f095..76e35fed 100644 --- a/SDWebImage/SDImageIOCoder.m +++ b/SDWebImage/SDImageIOCoder.m @@ -215,12 +215,12 @@ #else CGImagePropertyOrientation exifOrientation = kCGImagePropertyOrientationUp; #endif - [properties setValue:@(exifOrientation) forKey:(__bridge_transfer NSString *)kCGImagePropertyOrientation]; + [properties setValue:@(exifOrientation) forKey:(__bridge NSString *)kCGImagePropertyOrientation]; double compressionQuality = 1; if ([options valueForKey:SDImageCoderEncodeCompressionQuality]) { compressionQuality = [[options valueForKey:SDImageCoderEncodeCompressionQuality] doubleValue]; } - [properties setValue:@(compressionQuality) forKey:(__bridge_transfer NSString *)kCGImageDestinationLossyCompressionQuality]; + [properties setValue:@(compressionQuality) forKey:(__bridge NSString *)kCGImageDestinationLossyCompressionQuality]; // Add your image to the destination. CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); From 6398eedce84e1086a3ee576df1eec4c80a99322b Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 19 Jul 2018 01:03:41 +0800 Subject: [PATCH 217/361] Rename `sd_UTTypeFromSDImageFormat` to `sd_UTTypeFromImageFormat` --- SDWebImage/NSData+ImageContentType.h | 2 +- SDWebImage/NSData+ImageContentType.m | 2 +- SDWebImage/SDImageAPNGCoder.m | 4 ++-- SDWebImage/SDImageCoderHelper.m | 2 +- SDWebImage/SDImageGIFCoder.m | 4 ++-- SDWebImage/SDImageIOCoder.m | 4 ++-- Tests/Tests/SDCategoriesTests.m | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/SDWebImage/NSData+ImageContentType.h b/SDWebImage/NSData+ImageContentType.h index 117439d2..2a9f7e2b 100644 --- a/SDWebImage/NSData+ImageContentType.h +++ b/SDWebImage/NSData+ImageContentType.h @@ -37,7 +37,7 @@ typedef NS_ENUM(NSInteger, SDImageFormat) { * @param format Format as SDImageFormat * @return The UTType as CFStringRef */ -+ (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format CF_RETURNS_NOT_RETAINED; ++ (nonnull CFStringRef)sd_UTTypeFromImageFormat:(SDImageFormat)format CF_RETURNS_NOT_RETAINED; /** * Convert UTTyppe to SDImageFormat diff --git a/SDWebImage/NSData+ImageContentType.m b/SDWebImage/NSData+ImageContentType.m index 64ea0a30..89d5ae29 100644 --- a/SDWebImage/NSData+ImageContentType.m +++ b/SDWebImage/NSData+ImageContentType.m @@ -66,7 +66,7 @@ return SDImageFormatUndefined; } -+ (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format { ++ (nonnull CFStringRef)sd_UTTypeFromImageFormat:(SDImageFormat)format { CFStringRef UTType; switch (format) { case SDImageFormatJPEG: diff --git a/SDWebImage/SDImageAPNGCoder.m b/SDWebImage/SDImageAPNGCoder.m index 90f98063..f6259775 100644 --- a/SDWebImage/SDImageAPNGCoder.m +++ b/SDWebImage/SDImageAPNGCoder.m @@ -188,7 +188,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef } NSMutableData *imageData = [NSMutableData data]; - CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatPNG]; + CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:SDImageFormatPNG]; NSArray *frames = [SDImageCoderHelper framesFromAnimatedImage:image]; // Create an image destination. APNG does not support EXIF image orientation @@ -243,7 +243,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef - (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)options { self = [super init]; if (self) { - CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatPNG]; + CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:SDImageFormatPNG]; _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceTypeIdentifierHint : (__bridge NSString *)imageUTType}); CGFloat scale = 1; if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { diff --git a/SDWebImage/SDImageCoderHelper.m b/SDWebImage/SDImageCoderHelper.m index 765e676e..a0e741a4 100644 --- a/SDWebImage/SDImageCoderHelper.m +++ b/SDWebImage/SDImageCoderHelper.m @@ -80,7 +80,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over #else NSMutableData *imageData = [NSMutableData data]; - CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatGIF]; + CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:SDImageFormatGIF]; // Create an image destination. GIF does not support EXIF image orientation CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, frameCount, NULL); if (!imageDestination) { diff --git a/SDWebImage/SDImageGIFCoder.m b/SDWebImage/SDImageGIFCoder.m index 5dc55419..8936cf7b 100644 --- a/SDWebImage/SDImageGIFCoder.m +++ b/SDWebImage/SDImageGIFCoder.m @@ -183,7 +183,7 @@ - (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)options { self = [super init]; if (self) { - CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatGIF]; + CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:SDImageFormatGIF]; _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceTypeIdentifierHint : (__bridge NSString *)imageUTType}); CGFloat scale = 1; if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { @@ -271,7 +271,7 @@ } NSMutableData *imageData = [NSMutableData data]; - CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatGIF]; + CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:SDImageFormatGIF]; NSArray *frames = [SDImageCoderHelper framesFromAnimatedImage:image]; // Create an image destination. GIF does not support EXIF image orientation diff --git a/SDWebImage/SDImageIOCoder.m b/SDWebImage/SDImageIOCoder.m index 44826953..11ef5cf0 100644 --- a/SDWebImage/SDImageIOCoder.m +++ b/SDWebImage/SDImageIOCoder.m @@ -203,7 +203,7 @@ } NSMutableData *imageData = [NSMutableData data]; - CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:format]; + CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:format]; // Create an image destination. CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, 1, NULL); @@ -261,7 +261,7 @@ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSMutableData *imageData = [NSMutableData data]; - CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatHEIC]; + CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:SDImageFormatHEIC]; // Create an image destination. CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, 1, NULL); diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m index 36996529..35233945 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDCategoriesTests.m @@ -24,7 +24,7 @@ expect(format == SDImageFormatUndefined); // Test invalid format - CFStringRef type = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatUndefined]; + CFStringRef type = [NSData sd_UTTypeFromImageFormat:SDImageFormatUndefined]; expect(CFStringCompare(kUTTypePNG, type, 0)).equal(kCFCompareEqualTo); } From 05889b6b9cd2ffd019dbe4ed912d2fecb58dc5be Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Sat, 21 Jul 2018 23:44:06 +0800 Subject: [PATCH 218/361] Replace valueForKey with objectForKey when access NSDictionary --- SDWebImage/SDImageAPNGCoder.m | 28 ++++++++++++---------- SDWebImage/SDImageCache.m | 4 ++-- SDWebImage/SDImageCacheDefine.m | 14 +++++------ SDWebImage/SDImageGIFCoder.m | 28 ++++++++++++---------- SDWebImage/SDImageIOCoder.m | 19 ++++++++------- SDWebImage/SDImageLoader.m | 28 ++++++++++------------ SDWebImage/SDWebImageDownloader.m | 12 ++++------ SDWebImage/SDWebImageDownloaderOperation.m | 11 ++++++--- SDWebImage/SDWebImageManager.m | 18 +++++++------- SDWebImage/UIView+WebCache.m | 12 ++++------ SDWebImage/WebP/SDImageWebPCoder.m | 26 +++++++++++--------- 11 files changed, 103 insertions(+), 97 deletions(-) diff --git a/SDWebImage/SDImageAPNGCoder.m b/SDWebImage/SDImageAPNGCoder.m index f6259775..a7cea27b 100644 --- a/SDWebImage/SDImageAPNGCoder.m +++ b/SDWebImage/SDImageAPNGCoder.m @@ -81,8 +81,9 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef return nil; } CGFloat scale = 1; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } @@ -139,9 +140,9 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef - (NSUInteger)sd_imageLoopCountWithSource:(CGImageSourceRef)source { NSUInteger loopCount = 0; NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(source, nil); - NSDictionary *pngProperties = [imageProperties valueForKey:(__bridge NSString *)kCGImagePropertyPNGDictionary]; + NSDictionary *pngProperties = imageProperties[(__bridge NSString *)kCGImagePropertyPNGDictionary]; if (pngProperties) { - NSNumber *apngLoopCount = [pngProperties valueForKey:(__bridge NSString *)kCGImagePropertyAPNGLoopCount]; + NSNumber *apngLoopCount = pngProperties[(__bridge NSString *)kCGImagePropertyAPNGLoopCount]; if (apngLoopCount != nil) { loopCount = apngLoopCount.unsignedIntegerValue; } @@ -199,8 +200,8 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef } NSMutableDictionary *properties = [NSMutableDictionary dictionary]; double compressionQuality = 1; - if ([options valueForKey:SDImageCoderEncodeCompressionQuality]) { - compressionQuality = [[options valueForKey:SDImageCoderEncodeCompressionQuality] doubleValue]; + if (options[SDImageCoderEncodeCompressionQuality]) { + compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue]; } [properties setValue:@(compressionQuality) forKey:(__bridge NSString *)kCGImageDestinationLossyCompressionQuality]; @@ -246,8 +247,9 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:SDImageFormatPNG]; _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceTypeIdentifierHint : (__bridge NSString *)imageUTType}); CGFloat scale = 1; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } @@ -297,8 +299,9 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef if (partialImageRef) { CGFloat scale = _scale; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } @@ -334,8 +337,9 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef return nil; } CGFloat scale = 1; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 96ec13bc..2bcafc5e 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -355,9 +355,9 @@ return nil; } - if ([context valueForKey:SDWebImageContextImageTransformer]) { + id transformer = context[SDWebImageContextImageTransformer]; + if (transformer) { // grab the transformed disk image if transformer provided - id transformer = [context valueForKey:SDWebImageContextImageTransformer]; NSString *transformerKey = [transformer transformerKey]; key = SDTransformedKeyForKey(key, transformerKey); } diff --git a/SDWebImage/SDImageCacheDefine.m b/SDWebImage/SDImageCacheDefine.m index c6b7cc5a..e6ac6881 100644 --- a/SDWebImage/SDImageCacheDefine.m +++ b/SDWebImage/SDImageCacheDefine.m @@ -15,20 +15,18 @@ UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context) { UIImage *image; BOOL decodeFirstFrame = options & SDWebImageDecodeFirstFrameOnly; - NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor]; + NSNumber *scaleValue = context[SDWebImageContextImageScaleFactor]; CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); if (scale < 1) { scale = 1; } if (!decodeFirstFrame) { + Class animatedImageClass = context[SDWebImageContextAnimatedImageClass]; // check whether we should use `SDAnimatedImage` - if ([context valueForKey:SDWebImageContextAnimatedImageClass]) { - Class animatedImageClass = [context valueForKey:SDWebImageContextAnimatedImageClass]; - if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { - image = [[animatedImageClass alloc] initWithData:imageData scale:scale]; - if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { - [((id)image) preloadAllFrames]; - } + if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { + image = [[animatedImageClass alloc] initWithData:imageData scale:scale]; + if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { + [((id)image) preloadAllFrames]; } } } diff --git a/SDWebImage/SDImageGIFCoder.m b/SDWebImage/SDImageGIFCoder.m index 8936cf7b..41cd4e00 100644 --- a/SDWebImage/SDImageGIFCoder.m +++ b/SDWebImage/SDImageGIFCoder.m @@ -74,8 +74,9 @@ return nil; } CGFloat scale = 1; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } @@ -132,9 +133,9 @@ - (NSUInteger)sd_imageLoopCountWithSource:(CGImageSourceRef)source { NSUInteger loopCount = 1; NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(source, nil); - NSDictionary *gifProperties = [imageProperties valueForKey:(__bridge NSString *)kCGImagePropertyGIFDictionary]; + NSDictionary *gifProperties = imageProperties[(__bridge NSString *)kCGImagePropertyGIFDictionary]; if (gifProperties) { - NSNumber *gifLoopCount = [gifProperties valueForKey:(__bridge NSString *)kCGImagePropertyGIFLoopCount]; + NSNumber *gifLoopCount = gifProperties[(__bridge NSString *)kCGImagePropertyGIFLoopCount]; if (gifLoopCount != nil) { loopCount = gifLoopCount.unsignedIntegerValue; } @@ -186,8 +187,9 @@ CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:SDImageFormatGIF]; _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceTypeIdentifierHint : (__bridge NSString *)imageUTType}); CGFloat scale = 1; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } @@ -237,8 +239,9 @@ if (partialImageRef) { CGFloat scale = _scale; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } @@ -282,8 +285,8 @@ } NSMutableDictionary *properties = [NSMutableDictionary dictionary]; double compressionQuality = 1; - if ([options valueForKey:SDImageCoderEncodeCompressionQuality]) { - compressionQuality = [[options valueForKey:SDImageCoderEncodeCompressionQuality] doubleValue]; + if (options[SDImageCoderEncodeCompressionQuality]) { + compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue]; } [properties setValue:@(compressionQuality) forKey:(__bridge NSString *)kCGImageDestinationLossyCompressionQuality]; @@ -335,8 +338,9 @@ return nil; } CGFloat scale = 1; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } diff --git a/SDWebImage/SDImageIOCoder.m b/SDWebImage/SDImageIOCoder.m index 11ef5cf0..7a34ee8e 100644 --- a/SDWebImage/SDImageIOCoder.m +++ b/SDWebImage/SDImageIOCoder.m @@ -65,8 +65,9 @@ return nil; } CGFloat scale = 1; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } @@ -97,8 +98,9 @@ if (self) { _imageSource = CGImageSourceCreateIncremental(NULL); CGFloat scale = 1; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } @@ -153,8 +155,9 @@ if (partialImageRef) { CGFloat scale = _scale; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } @@ -220,8 +223,8 @@ #endif [properties setValue:@(exifOrientation) forKey:(__bridge NSString *)kCGImagePropertyOrientation]; double compressionQuality = 1; - if ([options valueForKey:SDImageCoderEncodeCompressionQuality]) { - compressionQuality = [[options valueForKey:SDImageCoderEncodeCompressionQuality] doubleValue]; + if (options[SDImageCoderEncodeCompressionQuality]) { + compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue]; } [properties setValue:@(compressionQuality) forKey:(__bridge NSString *)kCGImageDestinationLossyCompressionQuality]; diff --git a/SDWebImage/SDImageLoader.m b/SDWebImage/SDImageLoader.m index dbcf7f52..4d9531ba 100644 --- a/SDWebImage/SDImageLoader.m +++ b/SDWebImage/SDImageLoader.m @@ -21,7 +21,7 @@ UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Nonnull imageData, NS NSCParameterAssert(imageURL); UIImage *image; - id cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter]; + id cacheKeyFilter = context[SDWebImageContextCacheKeyFilter]; NSString *cacheKey; if (cacheKeyFilter) { cacheKey = [cacheKeyFilter cacheKeyForURL:imageURL]; @@ -29,20 +29,18 @@ UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Nonnull imageData, NS cacheKey = imageURL.absoluteString; } BOOL decodeFirstFrame = options & SDWebImageDecodeFirstFrameOnly; - NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor]; + NSNumber *scaleValue = context[SDWebImageContextImageScaleFactor]; CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); if (scale < 1) { scale = 1; } if (!decodeFirstFrame) { // check whether we should use `SDAnimatedImage` - if ([context valueForKey:SDWebImageContextAnimatedImageClass]) { - Class animatedImageClass = [context valueForKey:SDWebImageContextAnimatedImageClass]; - if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { - image = [[animatedImageClass alloc] initWithData:imageData scale:scale]; - if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { - [((id)image) preloadAllFrames]; - } + Class animatedImageClass = context[SDWebImageContextAnimatedImageClass]; + if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { + image = [[animatedImageClass alloc] initWithData:imageData scale:scale]; + if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { + [((id)image) preloadAllFrames]; } } } @@ -78,7 +76,7 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im NSCParameterAssert(operation); UIImage *image; - id cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter]; + id cacheKeyFilter = context[SDWebImageContextCacheKeyFilter]; NSString *cacheKey; if (cacheKeyFilter) { cacheKey = [cacheKeyFilter cacheKeyForURL:imageURL]; @@ -86,7 +84,7 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im cacheKey = imageURL.absoluteString; } BOOL decodeFirstFrame = options & SDWebImageDecodeFirstFrameOnly; - NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor]; + NSNumber *scaleValue = context[SDWebImageContextImageScaleFactor]; CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); if (scale < 1) { scale = 1; @@ -111,11 +109,9 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im [progressiveCoder updateIncrementalData:imageData finished:finished]; if (!decodeFirstFrame) { // check whether we should use `SDAnimatedImage` - if ([context valueForKey:SDWebImageContextAnimatedImageClass]) { - Class animatedImageClass = [context valueForKey:SDWebImageContextAnimatedImageClass]; - if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)] && [progressiveCoder conformsToProtocol:@protocol(SDAnimatedImageCoder)]) { - image = [[animatedImageClass alloc] initWithAnimatedCoder:(id)progressiveCoder scale:scale]; - } + Class animatedImageClass = context[SDWebImageContextAnimatedImageClass]; + if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)] && [progressiveCoder conformsToProtocol:@protocol(SDAnimatedImageCoder)]) { + image = [[animatedImageClass alloc] initWithAnimatedCoder:(id)progressiveCoder scale:scale]; } } if (!image) { diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 7dd3c7aa..f5f638d8 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -173,10 +173,8 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; mutableRequest.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies); mutableRequest.HTTPShouldUsePipelining = YES; mutableRequest.allHTTPHeaderFields = sself.HTTPHeaders; - id requestModifier; - if ([context valueForKey:SDWebImageContextDownloadRequestModifier]) { - requestModifier = [context valueForKey:SDWebImageContextDownloadRequestModifier]; - } else { + id requestModifier = context[SDWebImageContextDownloadRequestModifier]; + if (!requestModifier) { requestModifier = self.requestModifier; } @@ -475,10 +473,8 @@ didReceiveResponse:(NSURLResponse *)response } - (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDImageLoaderCompletedBlock)completedBlock { - UIImage *cachedImage; - if ([context valueForKey:SDWebImageContextLoaderCachedImage]) { - cachedImage = [context valueForKey:SDWebImageContextLoaderCachedImage]; - } + UIImage *cachedImage = context[SDWebImageContextLoaderCachedImage]; + SDWebImageDownloaderOptions downloaderOptions = 0; if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority; if (options & SDWebImageProgressiveLoad) downloaderOptions |= SDWebImageDownloaderProgressiveLoad; diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 5232400b..e69426ce 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -103,10 +103,15 @@ typedef NSMutableDictionary SDCallbacksDictionary; - (nullable NSArray *)callbacksForKey:(NSString *)key { LOCK(self.callbacksLock); - NSMutableArray *callbacks = [[self.callbackBlocks valueForKey:key] mutableCopy]; + NSArray *callbackBlocks = [self.callbackBlocks copy]; UNLOCK(self.callbacksLock); - // We need to remove [NSNull null] because there might not always be a progress block for each callback - [callbacks removeObjectIdenticalTo:[NSNull null]]; + NSMutableArray *callbacks = [NSMutableArray arrayWithCapacity:callbackBlocks.count]; + for (SDCallbacksDictionary *callbacksDic in callbackBlocks) { + id callback = callbacksDic[key]; + if (callback) { + [callbacks addObject:callback]; + } + } return [callbacks copy]; // strip mutability here } diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index a7238e83..33f5f6c6 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -189,7 +189,7 @@ static id _defaultImageLoader; // Check whether we should query cache BOOL shouldQueryCache = (options & SDWebImageFromLoaderOnly) == 0; if (shouldQueryCache) { - id cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter]; + id cacheKeyFilter = context[SDWebImageContextCacheKeyFilter]; NSString *key = [self cacheKeyForURL:url cacheKeyFilter:cacheKeyFilter]; __weak SDWebImageCombinedOperation *weakOperation = operation; operation.cacheOperation = [self.imageCache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable cachedImage, NSData * _Nullable cachedData, SDImageCacheType cacheType) { @@ -277,13 +277,13 @@ static id _defaultImageLoader; } SDImageCacheType storeCacheType = SDImageCacheTypeAll; - if ([context valueForKey:SDWebImageContextStoreCacheType]) { - storeCacheType = [[context valueForKey:SDWebImageContextStoreCacheType] unsignedIntegerValue]; + if (context[SDWebImageContextStoreCacheType]) { + storeCacheType = [context[SDWebImageContextStoreCacheType] integerValue]; } - id cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter]; + id cacheKeyFilter = context[SDWebImageContextCacheKeyFilter]; NSString *key = [self cacheKeyForURL:url cacheKeyFilter:cacheKeyFilter]; - id transformer = [context valueForKey:SDWebImageContextImageTransformer]; - id cacheSerializer = [context valueForKey:SDWebImageContextCacheKeyFilter]; + id transformer = context[SDWebImageContextImageTransformer]; + id cacheSerializer = context[SDWebImageContextCacheKeyFilter]; if (downloadedImage && (!downloadedImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage)) && transformer) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ UIImage *transformedImage = [transformer transformedImageWithImage:downloadedImage forKey:key]; @@ -369,17 +369,17 @@ static id _defaultImageLoader; SDWebImageMutableContext *mutableContext = [SDWebImageMutableContext dictionary]; // Image Transformer from manager - if (![context valueForKey:SDWebImageContextImageTransformer]) { + if (!context[SDWebImageContextImageTransformer]) { id transformer = self.transformer; [mutableContext setValue:transformer forKey:SDWebImageContextImageTransformer]; } // Cache key filter from manager - if (![context valueForKey:SDWebImageContextCacheKeyFilter]) { + if (!context[SDWebImageContextCacheKeyFilter]) { id cacheKeyFilter = self.cacheKeyFilter; [mutableContext setValue:cacheKeyFilter forKey:SDWebImageContextCacheKeyFilter]; } // Cache serializer from manager - if (![context valueForKey:SDWebImageContextCacheSerializer]) { + if (!context[SDWebImageContextCacheSerializer]) { id cacheSerializer = self.cacheSerializer; [mutableContext setValue:cacheSerializer forKey:SDWebImageContextCacheSerializer]; } diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 8a73d740..d7e73cd8 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -44,10 +44,8 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDInternalCompletionBlock)completedBlock { context = [context copy]; // copy to avoid mutable object - NSString *validOperationKey = nil; - if ([context valueForKey:SDWebImageContextSetImageOperationKey]) { - validOperationKey = [context valueForKey:SDWebImageContextSetImageOperationKey]; - } else { + NSString *validOperationKey = context[SDWebImageContextSetImageOperationKey]; + if (!validOperationKey) { validOperationKey = NSStringFromClass([self class]); } [self sd_cancelImageLoadOperationWithKey:validOperationKey]; @@ -70,10 +68,8 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; id imageIndicator = self.sd_imageIndicator; #endif - SDWebImageManager *manager; - if ([context valueForKey:SDWebImageContextCustomManager]) { - manager = (SDWebImageManager *)[context valueForKey:SDWebImageContextCustomManager]; - } else { + SDWebImageManager *manager = context[SDWebImageContextCustomManager]; + if (!manager) { manager = [SDWebImageManager sharedManager]; } diff --git a/SDWebImage/WebP/SDImageWebPCoder.m b/SDWebImage/WebP/SDImageWebPCoder.m index 83f641c4..56f6e6b4 100644 --- a/SDWebImage/WebP/SDImageWebPCoder.m +++ b/SDWebImage/WebP/SDImageWebPCoder.m @@ -112,10 +112,11 @@ uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS); BOOL hasAnimation = flags & ANIMATION_FLAG; - BOOL decodeFirstFrame = [[options valueForKey:SDImageCoderDecodeFirstFrameOnly] boolValue]; + BOOL decodeFirstFrame = [options[SDImageCoderDecodeFirstFrameOnly] boolValue]; CGFloat scale = 1; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } @@ -212,8 +213,9 @@ // Progressive images need transparent, so always use premultiplied BGRA _idec = WebPINewRGB(MODE_bgrA, NULL, 0, 0); CGFloat scale = 1; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } @@ -284,8 +286,9 @@ return nil; } CGFloat scale = _scale; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } @@ -425,8 +428,8 @@ NSData *data; double compressionQuality = 1; - if ([options valueForKey:SDImageCoderEncodeCompressionQuality]) { - compressionQuality = [[options valueForKey:SDImageCoderEncodeCompressionQuality] doubleValue]; + if (options[SDImageCoderEncodeCompressionQuality]) { + compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue]; } NSArray *frames = [SDImageCoderHelper framesFromAnimatedImage:image]; @@ -633,8 +636,9 @@ static void FreeImageData(void *info, const void *data, size_t size) { return nil; } CGFloat scale = 1; - if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; + NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; + if (scaleFactor != nil) { + scale = [scaleFactor doubleValue]; if (scale < 1) { scale = 1; } From 532a4d82294b2317fb947f7fe2b03acbaf22f8f3 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Tue, 24 Jul 2018 10:09:57 +0800 Subject: [PATCH 219/361] Replace setValue:forKey with syntactic sugar --- SDWebImage/SDImageAPNGCoder.m | 4 ++-- SDWebImage/SDImageGIFCoder.m | 4 ++-- SDWebImage/SDImageIOCoder.m | 4 ++-- SDWebImage/SDWebImageManager.m | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/SDWebImage/SDImageAPNGCoder.m b/SDWebImage/SDImageAPNGCoder.m index a7cea27b..8c58aa1b 100644 --- a/SDWebImage/SDImageAPNGCoder.m +++ b/SDWebImage/SDImageAPNGCoder.m @@ -203,7 +203,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef if (options[SDImageCoderEncodeCompressionQuality]) { compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue]; } - [properties setValue:@(compressionQuality) forKey:(__bridge NSString *)kCGImageDestinationLossyCompressionQuality]; + properties[(__bridge NSString *)kCGImageDestinationLossyCompressionQuality] = @(compressionQuality); BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; if (encodeFirstFrame || frames.count == 0) { @@ -213,7 +213,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef // for animated APNG images NSUInteger loopCount = image.sd_imageLoopCount; NSDictionary *pngProperties = @{(__bridge NSString *)kCGImagePropertyAPNGLoopCount : @(loopCount)}; - [properties setValue:pngProperties forKey:(__bridge NSString *)kCGImagePropertyPNGDictionary]; + properties[(__bridge NSString *)kCGImagePropertyPNGDictionary] = pngProperties; CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)properties); for (size_t i = 0; i < frames.count; i++) { diff --git a/SDWebImage/SDImageGIFCoder.m b/SDWebImage/SDImageGIFCoder.m index 41cd4e00..008a2b0b 100644 --- a/SDWebImage/SDImageGIFCoder.m +++ b/SDWebImage/SDImageGIFCoder.m @@ -288,7 +288,7 @@ if (options[SDImageCoderEncodeCompressionQuality]) { compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue]; } - [properties setValue:@(compressionQuality) forKey:(__bridge NSString *)kCGImageDestinationLossyCompressionQuality]; + properties[(__bridge NSString *)kCGImageDestinationLossyCompressionQuality] = @(compressionQuality); BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; if (encodeFirstFrame || frames.count == 0) { @@ -298,7 +298,7 @@ // for animated GIF images NSUInteger loopCount = image.sd_imageLoopCount; NSDictionary *gifProperties = @{(__bridge NSString *)kCGImagePropertyGIFLoopCount : @(loopCount)}; - [properties setValue:gifProperties forKey:(__bridge NSString *)kCGImagePropertyGIFDictionary]; + properties[(__bridge NSString *)kCGImagePropertyGIFDictionary] = gifProperties; CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)properties); for (size_t i = 0; i < frames.count; i++) { diff --git a/SDWebImage/SDImageIOCoder.m b/SDWebImage/SDImageIOCoder.m index 7a34ee8e..a103a265 100644 --- a/SDWebImage/SDImageIOCoder.m +++ b/SDWebImage/SDImageIOCoder.m @@ -221,12 +221,12 @@ #else CGImagePropertyOrientation exifOrientation = kCGImagePropertyOrientationUp; #endif - [properties setValue:@(exifOrientation) forKey:(__bridge NSString *)kCGImagePropertyOrientation]; + properties[(__bridge NSString *)kCGImagePropertyOrientation] = @(exifOrientation); double compressionQuality = 1; if (options[SDImageCoderEncodeCompressionQuality]) { compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue]; } - [properties setValue:@(compressionQuality) forKey:(__bridge NSString *)kCGImageDestinationLossyCompressionQuality]; + properties[(__bridge NSString *)kCGImageDestinationLossyCompressionQuality] = @(compressionQuality); // Add your image to the destination. CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 33f5f6c6..bddb4c85 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -233,7 +233,7 @@ static id _defaultImageLoader; } else { mutableContext = [NSMutableDictionary dictionary]; } - [mutableContext setValue:cachedImage forKey:SDWebImageContextLoaderCachedImage]; + mutableContext[SDWebImageContextLoaderCachedImage] = cachedImage; context = [mutableContext copy]; } From 2b7b5f5fa2fe3f7966b527ff60cd5cc6ef0efa41 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Tue, 24 Jul 2018 13:05:12 +0800 Subject: [PATCH 220/361] Use NSDictionary syntatic sugar --- SDWebImage/SDWebImageDownloader.m | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index f5f638d8..dfc39c57 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -134,11 +134,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; return; } NSMutableDictionary *mutableHTTPHeaders = [self.HTTPHeaders mutableCopy]; - if (value) { - [mutableHTTPHeaders setObject:value forKey:field]; - } else { - [mutableHTTPHeaders removeObjectForKey:field]; - } + [mutableHTTPHeaders setValue:value forKey:field]; self.HTTPHeaders = [mutableHTTPHeaders copy]; } @@ -272,7 +268,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; [sself.URLOperations removeObjectForKey:url]; UNLOCK(sself.operationsLock); }; - [self.URLOperations setObject:operation forKey:url]; + self.URLOperations[url] = operation; // Add operation to operation queue only after all configuration done according to Apple's doc. // `addOperation:` does not synchronously execute the `operation.completionBlock` so this will not cause deadlock. [self.downloadQueue addOperation:operation]; From 919751f2de55ccc4f3d5361d7d78d7a4d10ff4a8 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 24 Jul 2018 14:11:57 +0800 Subject: [PATCH 221/361] Change SDImageFormat to use `NS_TYPED_EXTENSIBLE_ENUM` instead of fixed enum, to allow custom coder plugin extern the define (#2400) * Change SDImageFormat to use `NS_TYPED_EXTENSIBLE_ENUM` instead of fixed enum, to allow custom coder plugin extern the define * Update the comment and indent about `SDImageFormat` --- SDWebImage/NSData+ImageContentType.h | 21 ++++++++++++--------- SDWebImage/SDImageCoder.h | 4 ++++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/SDWebImage/NSData+ImageContentType.h b/SDWebImage/NSData+ImageContentType.h index 2a9f7e2b..c5970cb4 100644 --- a/SDWebImage/NSData+ImageContentType.h +++ b/SDWebImage/NSData+ImageContentType.h @@ -10,15 +10,18 @@ #import #import "SDWebImageCompat.h" -typedef NS_ENUM(NSInteger, SDImageFormat) { - SDImageFormatUndefined = -1, - SDImageFormatJPEG = 0, - SDImageFormatPNG, - SDImageFormatGIF, - SDImageFormatTIFF, - SDImageFormatWebP, - SDImageFormatHEIC -}; +/** + You can use switch case like normal enum. It's also recommended to add a default case. You should not assume anything about the raw value. + For custom coder plugin, it can also extern the enum for supported format. See `SDImageCoder` for more detailed information. + */ +typedef NSInteger SDImageFormat NS_TYPED_EXTENSIBLE_ENUM; +static const SDImageFormat SDImageFormatUndefined = -1; +static const SDImageFormat SDImageFormatJPEG = 0; +static const SDImageFormat SDImageFormatPNG = 1; +static const SDImageFormat SDImageFormatGIF = 2; +static const SDImageFormat SDImageFormatTIFF = 3; +static const SDImageFormat SDImageFormatWebP = 4; +static const SDImageFormat SDImageFormatHEIC = 5; @interface NSData (ImageContentType) diff --git a/SDWebImage/SDImageCoder.h b/SDWebImage/SDImageCoder.h index ebf151b2..d6c7a735 100644 --- a/SDWebImage/SDImageCoder.h +++ b/SDWebImage/SDImageCoder.h @@ -72,6 +72,10 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeCompressio /** Returns YES if this coder can encode some image. Otherwise, it should be passed to another coder. + For custom coder which introduce new image format, you'd better define a new `SDImageFormat` using like this. If you're creating public coder plugin for new image format, also update `https://github.com/rs/SDWebImage/wiki/Coder-Plugin-List` to avoid same value been defined twice. + * @code + static const SDImageFormat SDImageFormatHEIF = 10; + * @endcode @param format The image format @return YES if this coder can encode the image, NO otherwise From ef3123984f011b21b11196af9f399013ff195b93 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 26 Jul 2018 16:43:09 +0800 Subject: [PATCH 222/361] Add SDImageCoderWebImageContext coder option, which allow custom coder plugin, to receive the context option from top-level API (Cache/Downloader/View Category) --- SDWebImage/SDImageCacheDefine.m | 8 +++++++- SDWebImage/SDImageCoder.h | 9 +++++++++ SDWebImage/SDImageCoder.m | 2 ++ SDWebImage/SDImageLoader.m | 16 ++++++++++++++-- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/SDWebImage/SDImageCacheDefine.m b/SDWebImage/SDImageCacheDefine.m index c6b7cc5a..a729d7ad 100644 --- a/SDWebImage/SDImageCacheDefine.m +++ b/SDWebImage/SDImageCacheDefine.m @@ -33,7 +33,13 @@ UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSS } } if (!image) { - image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}]; + SDImageCoderOptions *options = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; + if (context) { + SDImageCoderMutableOptions *mutableOptions = [options mutableCopy]; + [mutableOptions setValue:context forKey:SDImageCoderWebImageContext]; + options = [mutableOptions copy]; + } + image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:options]; } if (image) { BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; diff --git a/SDWebImage/SDImageCoder.h b/SDWebImage/SDImageCoder.h index d6c7a735..60b796ad 100644 --- a/SDWebImage/SDImageCoder.h +++ b/SDWebImage/SDImageCoder.h @@ -12,6 +12,7 @@ typedef NSString * SDImageCoderOption NS_STRING_ENUM; typedef NSDictionary SDImageCoderOptions; +typedef NSMutableDictionary SDImageCoderMutableOptions; #pragma mark - Coder Options // These options are for image decoding @@ -38,6 +39,14 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeFirstFrame */ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeCompressionQuality; +/** + A SDWebImageContext object which hold the original context options from top-level API. (SDWebImageContext) + This option is ignored for all built-in coders and take no effect. + But this may be useful for some custom coders, because some business logic may dependent on things other than image or image data inforamtion only. + See `SDWebImageContext` for more detailed information. + */ +FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderWebImageContext; + #pragma mark - Coder /** This is the image coder protocol to provide custom image decoding/encoding. diff --git a/SDWebImage/SDImageCoder.m b/SDWebImage/SDImageCoder.m index e2ac717b..c963376b 100644 --- a/SDWebImage/SDImageCoder.m +++ b/SDWebImage/SDImageCoder.m @@ -13,3 +13,5 @@ SDImageCoderOption const SDImageCoderDecodeScaleFactor = @"decodeScaleFactor"; SDImageCoderOption const SDImageCoderEncodeFirstFrameOnly = @"encodeFirstFrameOnly"; SDImageCoderOption const SDImageCoderEncodeCompressionQuality = @"encodeCompressionQuality"; + +SDImageCoderOption const SDImageCoderWebImageContext = @"webImageContext"; diff --git a/SDWebImage/SDImageLoader.m b/SDWebImage/SDImageLoader.m index dbcf7f52..4fe35e0f 100644 --- a/SDWebImage/SDImageLoader.m +++ b/SDWebImage/SDImageLoader.m @@ -47,7 +47,13 @@ UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Nonnull imageData, NS } } if (!image) { - image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}]; + SDImageCoderOptions *options = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; + if (context) { + SDImageCoderMutableOptions *mutableOptions = [options mutableCopy]; + [mutableOptions setValue:context forKey:SDImageCoderWebImageContext]; + options = [mutableOptions copy]; + } + image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:options]; } if (image) { BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; @@ -119,7 +125,13 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im } } if (!image) { - image = [progressiveCoder incrementalDecodedImageWithOptions:@{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}]; + SDImageCoderOptions *options = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; + if (context) { + SDImageCoderMutableOptions *mutableOptions = [options mutableCopy]; + [mutableOptions setValue:context forKey:SDImageCoderWebImageContext]; + options = [mutableOptions copy]; + } + image = [progressiveCoder incrementalDecodedImageWithOptions:options]; } if (image) { BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; From 45324efdc8da5c2f136153dce543075bbd7b36fe Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Tue, 24 Jul 2018 12:22:26 +0300 Subject: [PATCH 223/361] Updated the StarUML diagrams (actually smaller detailed diagrams) for 5.0 version + added a High Level Diagram (thanks to @dreampiggy) --- Docs/Diagrams/SDWebImage.mdj | 90184 ++++++++++++++++ Docs/Diagrams/SDWebImageCacheClassDiagram.png | Bin 0 -> 195766 bytes Docs/Diagrams/SDWebImageClassDiagram.png | Bin 0 -> 328031 bytes .../Diagrams/SDWebImageCodersClassDiagram.png | Bin 0 -> 113615 bytes Docs/Diagrams/SDWebImageHighLevelDiagram.jpeg | Bin 0 -> 209170 bytes .../Diagrams/SDWebImageLoaderClassDiagram.png | Bin 0 -> 169264 bytes .../SDWebImageManagerClassDiagram.png | Bin 0 -> 285557 bytes Docs/Diagrams/SDWebImageSequenceDiagram.png | Bin 0 -> 56292 bytes .../SDWebImageTopLevelClassDiagram.png | Bin 0 -> 150993 bytes Docs/SDWebImage.mdj | 22762 ---- Docs/SDWebImageClassDiagram.png | Bin 345477 -> 0 bytes Docs/SDWebImageSequenceDiagram.png | Bin 131867 -> 0 bytes README.md | 22 +- 13 files changed, 90204 insertions(+), 22764 deletions(-) create mode 100644 Docs/Diagrams/SDWebImage.mdj create mode 100644 Docs/Diagrams/SDWebImageCacheClassDiagram.png create mode 100644 Docs/Diagrams/SDWebImageClassDiagram.png create mode 100644 Docs/Diagrams/SDWebImageCodersClassDiagram.png create mode 100644 Docs/Diagrams/SDWebImageHighLevelDiagram.jpeg create mode 100644 Docs/Diagrams/SDWebImageLoaderClassDiagram.png create mode 100644 Docs/Diagrams/SDWebImageManagerClassDiagram.png create mode 100644 Docs/Diagrams/SDWebImageSequenceDiagram.png create mode 100644 Docs/Diagrams/SDWebImageTopLevelClassDiagram.png delete mode 100644 Docs/SDWebImage.mdj delete mode 100644 Docs/SDWebImageClassDiagram.png delete mode 100644 Docs/SDWebImageSequenceDiagram.png diff --git a/Docs/Diagrams/SDWebImage.mdj b/Docs/Diagrams/SDWebImage.mdj new file mode 100644 index 00000000..b26b7b17 --- /dev/null +++ b/Docs/Diagrams/SDWebImage.mdj @@ -0,0 +1,90184 @@ +{ + "_type": "Project", + "_id": "AAAAAAFF+h6SjaM2Hec=", + "name": "SDWebImage", + "ownedElements": [ + { + "_type": "UMLModel", + "_id": "AAAAAAFF+qBWK6M3Z8Y=", + "_parent": { + "$ref": "AAAAAAFF+h6SjaM2Hec=" + }, + "name": "SDWebImage Model", + "ownedElements": [ + { + "_type": "UMLClassDiagram", + "_id": "AAAAAAFF+qBtyKM79qY=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Overall Class Diagram", + "visible": true, + "defaultDiagram": true, + "ownedViews": [ + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFUmMqaTslne2E=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUmMqaT8lo2ag=", + "_parent": { + "$ref": "AAAAAAFUmMqaTslne2E=" + }, + "model": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUmMqaT8lpMw4=", + "_parent": { + "$ref": "AAAAAAFUmMqaT8lo2ag=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 989, + "top": 21, + "width": 209, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmMqaT8lqdv4=", + "_parent": { + "$ref": "AAAAAAFUmMqaT8lo2ag=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 989, + "top": 36, + "width": 209, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImagePrefetcherDelegate", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmMqaT8lrlno=", + "_parent": { + "$ref": "AAAAAAFUmMqaT8lo2ag=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 989, + "top": 51, + "width": 209, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmMqaT8ls+2c=", + "_parent": { + "$ref": "AAAAAAFUmMqaT8lo2ag=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 330, + "top": -678, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 984, + "top": 16, + "width": 219, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUmMqaT8lpMw4=" + }, + "nameLabel": { + "$ref": "AAAAAAFUmMqaT8lqdv4=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUmMqaT8lrlno=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmMqaT8ls+2c=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFUmMqaT8lt/Ps=", + "_parent": { + "$ref": "AAAAAAFUmMqaTslne2E=" + }, + "model": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 984, + "top": 69, + "width": 243, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFUmMqaUMluvjM=", + "_parent": { + "$ref": "AAAAAAFUmMqaTslne2E=" + }, + "model": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmMqaV8mN2MY=", + "_parent": { + "$ref": "AAAAAAFUmMqaUMluvjM=" + }, + "model": { + "$ref": "AAAAAAFUkht/NI1jZE4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 845, + "top": 50, + "width": 248.10009765625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+didPrefetchURL:()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmMqaWMmQbyY=", + "_parent": { + "$ref": "AAAAAAFUmMqaUMluvjM=" + }, + "model": { + "$ref": "AAAAAAFUkhu8u41n4Ps=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 845, + "top": 65, + "width": 248.10009765625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+didFinishWithTotalCount:()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 984, + "top": 69, + "width": 258.10009765625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFUmMqaUMlvfNw=", + "_parent": { + "$ref": "AAAAAAFUmMqaTslne2E=" + }, + "model": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 165, + "top": -339, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFUmMqaUMlwiGQ=", + "_parent": { + "$ref": "AAAAAAFUmMqaTslne2E=" + }, + "model": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 165, + "top": -339, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 984, + "top": 16, + "width": 243, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUmMqaT8lo2ag=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFUmMqaT8lt/Ps=" + }, + "operationCompartment": { + "$ref": "AAAAAAFUmMqaUMluvjM=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFUmMqaUMlvfNw=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFUmMqaUMlwiGQ=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFUmMuDNcmaKIo=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUmMuDNcmbtbk=", + "_parent": { + "$ref": "AAAAAAFUmMuDNcmaKIo=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUmMuDNsmcNWY=", + "_parent": { + "$ref": "AAAAAAFUmMuDNcmbtbk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -184, + "top": -188, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmMuDNsmduFE=", + "_parent": { + "$ref": "AAAAAAFUmMuDNcmbtbk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 381, + "top": 223, + "width": 136, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageManager", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmMuDNsmeXJQ=", + "_parent": { + "$ref": "AAAAAAFUmMuDNcmbtbk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 381, + "top": 238, + "width": 136, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmMuDNsmfU3g=", + "_parent": { + "$ref": "AAAAAAFUmMuDNcmbtbk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -184, + "top": -188, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 376, + "top": 216, + "width": 146, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUmMuDNsmcNWY=" + }, + "nameLabel": { + "$ref": "AAAAAAFUmMuDNsmduFE=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUmMuDNsmeXJQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmMuDNsmfU3g=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFUmMuDNsmgAkg=", + "_parent": { + "$ref": "AAAAAAFUmMuDNcmaKIo=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFUmMuDPsnATeQ=", + "_parent": { + "$ref": "AAAAAAFUmMuDNsmgAkg=" + }, + "model": { + "$ref": "AAAAAAFUkiBj3o4EzZs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 181, + "width": 546.36181640625, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedManager", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky2Hb3A+QHOQ=", + "_parent": { + "$ref": "AAAAAAFUmMuDNsmgAkg=" + }, + "model": { + "$ref": "AAAAAAFky2HbvA+NZl4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 196, + "width": 546.36181640625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+delegate: SDWebImageManagerDelegate", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky2J/zxG37Ew=", + "_parent": { + "$ref": "AAAAAAFUmMuDNsmgAkg=" + }, + "model": { + "$ref": "AAAAAAFky2J/rxG0jPU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 211, + "width": 546.36181640625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageCache: SDImageCache", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky2KxzhMCOO4=", + "_parent": { + "$ref": "AAAAAAFUmMuDNsmgAkg=" + }, + "model": { + "$ref": "AAAAAAFky2KxrxL/YZE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 226, + "width": 546.36181640625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageLoader: SDImageLoader", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky2LeAhRNPeo=", + "_parent": { + "$ref": "AAAAAAFUmMuDNsmgAkg=" + }, + "model": { + "$ref": "AAAAAAFky2Ld4BRKPO4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 241, + "width": 546.36181640625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+transformer: SDImageTransformer", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky2MdWRXpHJ4=", + "_parent": { + "$ref": "AAAAAAFUmMuDNsmgAkg=" + }, + "model": { + "$ref": "AAAAAAFky2MdORXm73I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 256, + "width": 546.36181640625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cacheKeyFilter: SDWebImageCacheKeyFilter", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky2ND6Rc0ls0=", + "_parent": { + "$ref": "AAAAAAFUmMuDNsmgAkg=" + }, + "model": { + "$ref": "AAAAAAFky2NDyRcxc0E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 271, + "width": 546.36181640625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cacheSerializer: SDWebImageCacheSerializer", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky2OkKxh/xe4=", + "_parent": { + "$ref": "AAAAAAFUmMuDNsmgAkg=" + }, + "model": { + "$ref": "AAAAAAFky2OkAhh8hEE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 286, + "width": 546.36181640625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+running", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky2PU1BnKtes=", + "_parent": { + "$ref": "AAAAAAFUmMuDNsmgAkg=" + }, + "model": { + "$ref": "AAAAAAFky2PUsxnHAYw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 301, + "width": 546.36181640625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+defaultImageCache: SDImageCache", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky2P67BsVyU8=", + "_parent": { + "$ref": "AAAAAAFUmMuDNsmgAkg=" + }, + "model": { + "$ref": "AAAAAAFky2P6zBsSQ7s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 316, + "width": 546.36181640625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+defaultImageLoader: SDImageLoader", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 376, + "top": 256, + "width": 556.36181640625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFUmMuDNsmh7I4=", + "_parent": { + "$ref": "AAAAAAFUmMuDNcmaKIo=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky2Q6PRxgyJE=", + "_parent": { + "$ref": "AAAAAAFUmMuDNsmh7I4=" + }, + "model": { + "$ref": "AAAAAAFky2Q6HRxddGo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 339, + "width": 546.36181640625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(cache, loader)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmMuDQMnGch8=", + "_parent": { + "$ref": "AAAAAAFUmMuDNsmh7I4=" + }, + "model": { + "$ref": "AAAAAAFUkh/xZ44AqYk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 354, + "width": 546.36181640625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+loadImage(url, options, context, progressBlock, completedBlock): CombinedOperatiom", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmNLtc9LfCP8=", + "_parent": { + "$ref": "AAAAAAFUmMuDNsmh7I4=" + }, + "model": { + "$ref": "AAAAAAFUmNLtYNLc08o=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 369, + "width": 546.36181640625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cancelAll()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmNOR2tQ4Agg=", + "_parent": { + "$ref": "AAAAAAFUmMuDNsmh7I4=" + }, + "model": { + "$ref": "AAAAAAFUmNORx9Q1mi4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 384, + "width": 546.36181640625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cacheKey(url): String", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 376, + "top": 414, + "width": 556.36181640625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFUmMuDNsmiBHA=", + "_parent": { + "$ref": "AAAAAAFUmMuDNcmaKIo=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -100, + "top": -70, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFUmMuDNsmjAGU=", + "_parent": { + "$ref": "AAAAAAFUmMuDNcmaKIo=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -100, + "top": -70, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 376, + "top": 216, + "width": 146, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUmMuDNcmbtbk=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFUmMuDNsmgAkg=" + }, + "operationCompartment": { + "$ref": "AAAAAAFUmMuDNsmh7I4=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFUmMuDNsmiBHA=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFUmMuDNsmjAGU=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFUmMuQRcnK0vE=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUmMuQRcnL+Ic=", + "_parent": { + "$ref": "AAAAAAFUmMuQRcnK0vE=" + }, + "model": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUmMuQRsnM1vc=", + "_parent": { + "$ref": "AAAAAAFUmMuQRcnL+Ic=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 484, + "top": -238, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmMuQRsnNOeI=", + "_parent": { + "$ref": "AAAAAAFUmMuQRcnL+Ic=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 23, + "width": 146, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImagePrefetcher", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmMuQRsnO2JI=", + "_parent": { + "$ref": "AAAAAAFUmMuQRcnL+Ic=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 38, + "width": 146, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmMuQRsnPnXU=", + "_parent": { + "$ref": "AAAAAAFUmMuQRcnL+Ic=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 484, + "top": -238, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 784, + "top": 16, + "width": 156, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUmMuQRsnM1vc=" + }, + "nameLabel": { + "$ref": "AAAAAAFUmMuQRsnNOeI=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUmMuQRsnO2JI=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmMuQRsnPnXU=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFUmMuQRsnQWLc=", + "_parent": { + "$ref": "AAAAAAFUmMuQRcnK0vE=" + }, + "model": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFUmM4z4Ms1XuY=", + "_parent": { + "$ref": "AAAAAAFUmMuQRsnQWLc=" + }, + "model": { + "$ref": "AAAAAAFUmM4zy8syqFU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 765, + "top": 61, + "width": 268.7978515625, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedImagePrefetcher", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk0LGPYUYb938=", + "_parent": { + "$ref": "AAAAAAFUmMuQRsnQWLc=" + }, + "model": { + "$ref": "AAAAAAFk0LGPQUYY/Mk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 765, + "top": 76, + "width": 268.7978515625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+delegate: SDWebImagePrefetcherDelegate", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFUmMwm/8n0wzU=", + "_parent": { + "$ref": "AAAAAAFUmMuQRsnQWLc=" + }, + "model": { + "$ref": "AAAAAAFUmMwm7Mnxz9U=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 765, + "top": 91, + "width": 268.7978515625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+options: SDWebImageOptions", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 784, + "top": 56, + "width": 278.7978515625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFUmMuQRsnRij4=", + "_parent": { + "$ref": "AAAAAAFUmMuQRcnK0vE=" + }, + "model": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmM3db8r4CB0=", + "_parent": { + "$ref": "AAAAAAFUmMuQRsnRij4=" + }, + "model": { + "$ref": "AAAAAAFUmM3dVsr1bHY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 765, + "top": 114, + "width": 268.7978515625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+prefetchURLs:()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmNCMls5nNcg=", + "_parent": { + "$ref": "AAAAAAFUmMuQRsnRij4=" + }, + "model": { + "$ref": "AAAAAAFUmNCMgs5kwbc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 765, + "top": 129, + "width": 268.7978515625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cancelPrefetching()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 784, + "top": 109, + "width": 278.7978515625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFUmMuQRsnSrDo=", + "_parent": { + "$ref": "AAAAAAFUmMuQRcnK0vE=" + }, + "model": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 426, + "top": 1, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFUmMuQRsnTfoU=", + "_parent": { + "$ref": "AAAAAAFUmMuQRcnK0vE=" + }, + "model": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 882.55322265625, + "top": 136, + "width": 130.6689453125, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 784, + "top": 16, + "width": 156, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUmMuQRcnL+Ic=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFUmMuQRsnQWLc=" + }, + "operationCompartment": { + "$ref": "AAAAAAFUmMuQRsnRij4=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFUmMuQRsnSrDo=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFUmMuQRsnTfoU=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFUmMzgacoAUuo=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZcn8MSQ=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmMzgacoBVB4=", + "_parent": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZcn8MSQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 786, + "top": 237, + "width": 62.36572265625, + "height": 13, + "autoResize": false, + "alpha": -4.532535318640983, + "distance": 44.721359549995796, + "hostEdge": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "edgePosition": 1, + "underline": false, + "text": "+manager", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmMzgasoCSHw=", + "_parent": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZcn8MSQ=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 831, + "top": 228, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmMzgasoD8nA=", + "_parent": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZcn8MSQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 876, + "top": 229, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmMzgasoEAKU=", + "_parent": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn92Qw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 546, + "top": 214, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmMzgasoFRR4=", + "_parent": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn92Qw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 549, + "top": 200, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmMzgasoGgow=", + "_parent": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn92Qw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 542, + "top": 241, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmMzgasoHXlE=", + "_parent": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn+nz8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 846, + "top": 74, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmMzgasoIWBc=", + "_parent": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn+nz8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 832, + "top": 77, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmMzgasoJ3AM=", + "_parent": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn+nz8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 873, + "top": 70, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFUmMzgasoKSrI=", + "_parent": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn92Qw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFUmMzga8oL6Mo=", + "_parent": { + "$ref": "AAAAAAFUmMzgacoAUuo=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn+nz8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmMuQRcnK0vE=" + }, + "tail": { + "$ref": "AAAAAAFUmMuDNcmaKIo=" + }, + "lineStyle": 0, + "points": "521:235;861:235;861:55", + "stereotypeDisplay": "none", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFUmMzgacoBVB4=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFUmMzgasoCSHw=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmMzgasoD8nA=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFUmMzgasoEAKU=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFUmMzgasoFRR4=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFUmMzgasoGgow=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFUmMzgasoHXlE=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFUmMzgasoIWBc=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFUmMzgasoJ3AM=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFUmMzgasoKSrI=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFUmMzga8oL6Mo=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFUmM8TrMut8mA=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmM8TqsupT40=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmM8TrcuutTY=", + "_parent": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "model": { + "$ref": "AAAAAAFUmM8TqsupT40=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 930, + "top": 7, + "width": 60.9501953125, + "height": 13, + "autoResize": false, + "alpha": -1.5152983753953508, + "distance": 18.027756377319946, + "hostEdge": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "edgePosition": 1, + "underline": false, + "text": "+delegate", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmM8Trcuv5wo=", + "_parent": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "model": { + "$ref": "AAAAAAFUmM8TqsupT40=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 960, + "top": 56, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmM8Trcuwg1A=", + "_parent": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "model": { + "$ref": "AAAAAAFUmM8TqsupT40=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 961, + "top": 11, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmM8TrcuxMbs=", + "_parent": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuqc7A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 958, + "top": 40, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmM8Trcuy2Xg=", + "_parent": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuqc7A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 955, + "top": 54, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmM8TrcuzvFU=", + "_parent": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuqc7A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 962, + "top": 13, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmM8Trcu0K9c=", + "_parent": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuru94=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 964, + "top": 40, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmM8Trsu1cfo=", + "_parent": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuru94=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 967, + "top": 54, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmM8Trsu2kfM=", + "_parent": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuru94=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 960, + "top": 13, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFUmM8Trsu30do=", + "_parent": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuqc7A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 376, + "top": 344, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFUmM8Trsu4Iks=", + "_parent": { + "$ref": "AAAAAAFUmM8TrMut8mA=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuru94=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 376, + "top": 344, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmMuQRcnK0vE=" + }, + "tail": { + "$ref": "AAAAAAFUmMqaTslne2E=" + }, + "lineStyle": 0, + "points": "984:32;939:32", + "stereotypeDisplay": "none", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFUmM8TrcuutTY=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFUmM8Trcuv5wo=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmM8Trcuwg1A=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFUmM8TrcuxMbs=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFUmM8Trcuy2Xg=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFUmM8TrcuzvFU=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFUmM8Trcu0K9c=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFUmM8Trsu1cfo=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFUmM8Trsu2kfM=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFUmM8Trsu30do=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFUmM8Trsu4Iks=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFUmNDrqc6u4Jg=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUmNDrqc6vaig=", + "_parent": { + "$ref": "AAAAAAFUmNDrqc6u4Jg=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUmNDrqs6wj8c=", + "_parent": { + "$ref": "AAAAAAFUmNDrqc6vaig=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 221, + "width": 199, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmNDrqs6xyQA=", + "_parent": { + "$ref": "AAAAAAFUmNDrqc6vaig=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 236, + "width": 199, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageManagerDelegate", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmNDrqs6yURY=", + "_parent": { + "$ref": "AAAAAAFUmNDrqc6vaig=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 251, + "width": 199, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmNDrqs6zC2E=", + "_parent": { + "$ref": "AAAAAAFUmNDrqc6vaig=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -906, + "top": -218, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 216, + "width": 209, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUmNDrqs6wj8c=" + }, + "nameLabel": { + "$ref": "AAAAAAFUmNDrqs6xyQA=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUmNDrqs6yURY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmNDrqs6zC2E=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFUmNDrqs60TV0=", + "_parent": { + "$ref": "AAAAAAFUmNDrqc6u4Jg=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 261, + "width": 233, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFUmNDrq861Hmk=", + "_parent": { + "$ref": "AAAAAAFUmNDrqc6u4Jg=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmNDrt87aqWo=", + "_parent": { + "$ref": "AAAAAAFUmNDrq861Hmk=" + }, + "model": { + "$ref": "AAAAAAFUkh6LiI3wgxM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 10, + "width": 237.06787109375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+shouldDownloadImageForURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmNDruM7d5ZU=", + "_parent": { + "$ref": "AAAAAAFUmNDrq861Hmk=" + }, + "model": { + "$ref": "AAAAAAFUkh65uI30vRk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 25, + "width": 237.06787109375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+shouldBlockFailedURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 269, + "width": 247.06787109375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFUmNDrq862uls=", + "_parent": { + "$ref": "AAAAAAFUmNDrqc6u4Jg=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -453, + "top": -117, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFUmNDrq8634fU=", + "_parent": { + "$ref": "AAAAAAFUmNDrqc6u4Jg=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -453, + "top": -117, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 216, + "width": 233, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUmNDrqc6vaig=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFUmNDrqs60TV0=" + }, + "operationCompartment": { + "$ref": "AAAAAAFUmNDrq861Hmk=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFUmNDrq862uls=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFUmNDrq8634fU=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFUmNGSidAM2EA=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAIwc4=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNGSitANy3Q=", + "_parent": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAIwc4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 367, + "top": 247, + "width": 60.9501953125, + "height": 13, + "autoResize": false, + "alpha": -0.15602482575330162, + "distance": 90.09439494219383, + "hostEdge": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "edgePosition": 1, + "underline": false, + "text": "+delegate", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNGSitAOfz8=", + "_parent": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAIwc4=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 308, + "top": 204, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNGSi9AP6Jk=", + "_parent": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAIwc4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 308, + "top": 249, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNGSi9AQtHM=", + "_parent": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAJw9E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 265, + "top": 219, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNGSi9ARhW0=", + "_parent": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAJw9E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 268, + "top": 205, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNGSi9AS+50=", + "_parent": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAJw9E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 261, + "top": 246, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNGSi9ATBrA=", + "_parent": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAKXzo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 350, + "top": 219, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNGSi9AUntg=", + "_parent": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAKXzo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 347, + "top": 205, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNGSi9AVGbU=", + "_parent": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAKXzo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 354, + "top": 246, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFUmNGSi9AWHN8=", + "_parent": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAJw9E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 72, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFUmNGSjNAX0Ko=", + "_parent": { + "$ref": "AAAAAAFUmNGSidAM2EA=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAKXzo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 72, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmMuDNcmaKIo=" + }, + "tail": { + "$ref": "AAAAAAFUmNDrqc6u4Jg=" + }, + "lineStyle": 0, + "points": "240:240;376:240", + "stereotypeDisplay": "none", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFUmNGSitANy3Q=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFUmNGSitAOfz8=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmNGSi9AP6Jk=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFUmNGSi9AQtHM=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFUmNGSi9ARhW0=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFUmNGSi9AS+50=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFUmNGSi9ATBrA=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFUmNGSi9AUntg=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFUmNGSi9AVGbU=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFUmNGSi9AWHN8=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFUmNGSjNAX0Ko=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFUmNWcUNb3p+o=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUmNWcUNb4uJQ=", + "_parent": { + "$ref": "AAAAAAFUmNWcUNb3p+o=" + }, + "model": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUmNWcUdb5KuU=", + "_parent": { + "$ref": "AAAAAAFUmNWcUNb4uJQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1109, + "top": 133, + "width": 154, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmNWcUdb69zw=", + "_parent": { + "$ref": "AAAAAAFUmNWcUNb4uJQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1109, + "top": 148, + "width": 154, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageOperation", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmNWcUdb7XbE=", + "_parent": { + "$ref": "AAAAAAFUmNWcUNb4uJQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1109, + "top": 163, + "width": 154, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmNWcUdb83AA=", + "_parent": { + "$ref": "AAAAAAFUmNWcUNb4uJQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1870, + "top": -1206, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1104, + "top": 128, + "width": 164, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUmNWcUdb5KuU=" + }, + "nameLabel": { + "$ref": "AAAAAAFUmNWcUdb69zw=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUmNWcUdb7XbE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmNWcUdb83AA=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFUmNWcUdb9dh8=", + "_parent": { + "$ref": "AAAAAAFUmNWcUNb3p+o=" + }, + "model": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 935, + "top": -603, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFUmNWcUtb+mBY=", + "_parent": { + "$ref": "AAAAAAFUmNWcUNb3p+o=" + }, + "model": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmNWcdtcm+vY=", + "_parent": { + "$ref": "AAAAAAFUmNWcUtb+mBY=" + }, + "model": { + "$ref": "AAAAAAFUmNWHXtbX7L0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1061, + "top": 146, + "width": 187.28955078125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cancel()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1104, + "top": 181, + "width": 197.28955078125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFUmNWcUtb/20U=", + "_parent": { + "$ref": "AAAAAAFUmNWcUNb3p+o=" + }, + "model": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 935, + "top": -603, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFUmNWcUtcAYow=", + "_parent": { + "$ref": "AAAAAAFUmNWcUNb3p+o=" + }, + "model": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 935, + "top": -603, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1104, + "top": 128, + "width": 188, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUmNWcUNb4uJQ=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFUmNWcUdb9dh8=" + }, + "operationCompartment": { + "$ref": "AAAAAAFUmNWcUtb+mBY=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFUmNWcUtb/20U=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFUmNWcUtcAYow=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFUmNdXmNnpp1I=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUmNdXmNnqYDc=", + "_parent": { + "$ref": "AAAAAAFUmNdXmNnpp1I=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUmNdXmNnr5H4=", + "_parent": { + "$ref": "AAAAAAFUmNdXmNnqYDc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 36, + "top": -430, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmNdXmdnsoJE=", + "_parent": { + "$ref": "AAAAAAFUmNdXmNnqYDc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 301, + "top": 407, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmNdXmdntTaY=", + "_parent": { + "$ref": "AAAAAAFUmNdXmNnqYDc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 301, + "top": 422, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmNdXmdnuoqs=", + "_parent": { + "$ref": "AAAAAAFUmNdXmNnqYDc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 36, + "top": -430, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 296, + "top": 400, + "width": 128, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUmNdXmNnr5H4=" + }, + "nameLabel": { + "$ref": "AAAAAAFUmNdXmdnsoJE=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUmNdXmdntTaY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmNdXmdnuoqs=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFUmNdXmdnvJXE=", + "_parent": { + "$ref": "AAAAAAFUmNdXmNnpp1I=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFUmNdXptoY03w=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnvJXE=" + }, + "model": { + "$ref": "AAAAAAFUkiFzJY5gThM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 13, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedImageCache", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk0LaBFVtt1Go=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnvJXE=" + }, + "model": { + "$ref": "AAAAAAFk0LaA7lthFIA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 28, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+config: SDImageCacheConfig", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFUmPDDBhpeNqc=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnvJXE=" + }, + "model": { + "$ref": "AAAAAAFUmPDC7hpSvPQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 43, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+diskCachePath", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFUmPDhwxsZ7GE=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnvJXE=" + }, + "model": { + "$ref": "AAAAAAFUmPDhrRsNyCc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 58, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+additionalCachePathBlock", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 296, + "top": 440, + "width": 449.60693359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFUmNdXmdnwtCw=", + "_parent": { + "$ref": "AAAAAAFUmNdXmNnpp1I=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmPHYtR7bgKE=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFUmPHYnB7PNs4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 81, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(namespace, diskCacheDirectory, config)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmPTT5SgNlm4=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFUmPTT0CgBzK8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 96, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cachePath(key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmPMOcCH4C2s=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFUmPMOWiHsOa0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 111, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+store(image, imageData, key, toDisk, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmPMtWSKzkFI=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFUmPMtQiKnVfM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 126, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+storeImage(image, key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0NC0keZ8ro8=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFk0NC0bOZw4VQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 141, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+storeImageData(imageData, key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0NF3k+skLew=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFk0NF3Z+sY0tc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 156, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+diskImageExists(key, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0NJKRvAJ5AY=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFk0NJKG+/90EA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 171, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+diskImageDataExists(key): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0NLcyvVo6V8=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFk0NLcpfVc3Q8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 186, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+diskImageData(key): Data", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0NOW7fpNRrQ=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFk0NOWwPpBKis=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 201, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+queryCacheOperation(key, options, context, doneBlock): NSOperation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmPOk6SRm1Mk=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFUmPOk0iRaSME=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 216, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageFromMemoryCache(key): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmPPBnSUhpyE=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFUmPPBiSUVHSU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 231, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageFromDiskCache(key): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0NaQ8Qr6wFU=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFk0NaQzAru2sk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 246, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageFromCache(key): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmPPi2SXcgfY=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFUmPPiwSXQs7U=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 261, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeImage(key, fromDisk, completion)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0NfB9hJ9dqQ=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFk0NfB0BJxwa0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 276, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeImageFromMemory(key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0NhS7hd/d/Y=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFk0NhSwxdz+po=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 291, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeImageFromDisk(key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmPQzdyaXBMo=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFUmPQzYSaLCQc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 306, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+clearMemory()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmPRYeidSwZM=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFUmPRYYSdGCZA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 321, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+clearDIsk(completion)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmPT4dSjIhS0=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFUmPT4WSi8pg0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 336, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+deleteOldFiles(completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0Nk9kxz6CNQ=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFk0Nk9Zhzuux0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 351, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+getSize(): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0NmTnB9ArI0=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFk0NmTbx80+MQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 366, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+getDiskCount(): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0Nn3FiGGrrs=", + "_parent": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "model": { + "$ref": "AAAAAAFk0Nn28SF6Hq4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 357, + "top": 381, + "width": 439.60693359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+calculateSize(completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 296, + "top": 508, + "width": 449.60693359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFUmNdXmtnxgxw=", + "_parent": { + "$ref": "AAAAAAFUmNdXmNnpp1I=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 26, + "top": -247, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFUmNdXmtnyo9g=", + "_parent": { + "$ref": "AAAAAAFUmNdXmNnpp1I=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 26, + "top": -247, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 296, + "top": 400, + "width": 128, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUmNdXmNnqYDc=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFUmNdXmdnvJXE=" + }, + "operationCompartment": { + "$ref": "AAAAAAFUmNdXmdnwtCw=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFUmNdXmtnxgxw=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFUmNdXmtnyo9g=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFUmNdyjto3Jy4=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUmNdyjto42rU=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto3Jy4=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUmNdyjto5HIE=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto42rU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -108, + "top": -508, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmNdyjto60Nw=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto42rU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 485, + "top": 407, + "width": 157, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloader", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmNdyjto7L04=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto42rU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 485, + "top": 422, + "width": 157, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmNdyjto8yMo=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto42rU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -108, + "top": -508, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 480, + "top": 400, + "width": 167, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUmNdyjto5HIE=" + }, + "nameLabel": { + "$ref": "AAAAAAFUmNdyjto60Nw=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUmNdyjto7L04=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmNdyjto8yMo=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFUmNdyjto9J7o=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto3Jy4=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFUmNdymdpmxgM=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto9J7o=" + }, + "model": { + "$ref": "AAAAAAFUkiJAhI5kL78=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 13, + "width": 551.32568359375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedDownloader", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFUmOMr6uw/dL0=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto9J7o=" + }, + "model": { + "$ref": "AAAAAAFUmOMr1ewzvaI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 28, + "width": 551.32568359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+config: SDWebImageDownloaderConfig", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFUmONDyez68BQ=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto9J7o=" + }, + "model": { + "$ref": "AAAAAAFUmONDtOzuN2c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 43, + "width": 551.32568359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+requestModifier: SDWebImageDownloaderRequestModifier", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFUmOaPhvpHGUQ=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto9J7o=" + }, + "model": { + "$ref": "AAAAAAFUmOaPcvo7CuM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 58, + "width": 551.32568359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sessionConfiguration", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFUmOa8FvsCenQ=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto9J7o=" + }, + "model": { + "$ref": "AAAAAAFUmOa7+/r2ysU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 73, + "width": 551.32568359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+suspended", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFUmOiC6/5m4L8=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto9J7o=" + }, + "model": { + "$ref": "AAAAAAFUmOiCz/5aGv0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 88, + "width": 551.32568359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+currentDownloadCount", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 480, + "top": 440, + "width": 561.32568359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFUmNdyjto+23Y=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto3Jy4=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFXmuCd5HfZ18A=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto+23Y=" + }, + "model": { + "$ref": "AAAAAAFXmuCdynfN50Y=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 111, + "width": 551.32568359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(config)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmOeiAvwXuks=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto+23Y=" + }, + "model": { + "$ref": "AAAAAAFUmOeh6PwLtkk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 126, + "width": 551.32568359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+setValue(value, HTTPHeaderField)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky3dFR4XlRm8=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto+23Y=" + }, + "model": { + "$ref": "AAAAAAFky3dFIIXZ21M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 141, + "width": 551.32568359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+value(HTTPHeaderField): String", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmOOiz+21uaI=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto+23Y=" + }, + "model": { + "$ref": "AAAAAAFUmOOite2pkfo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 156, + "width": 551.32568359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+downloadImage(url, options, context, progressBlock, completedBlock): DownloadToken", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmOgcM/2NAEM=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto+23Y=" + }, + "model": { + "$ref": "AAAAAAFUmOgcH/2BRjw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 171, + "width": 551.32568359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cancelAllDownloads()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmOZtyvmMqac=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto+23Y=" + }, + "model": { + "$ref": "AAAAAAFUmOZtsvmAcFQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 186, + "width": 551.32568359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+invalidateSessionAndCancel()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 480, + "top": 538, + "width": 561.32568359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFUmNdyj9o/7Mk=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto3Jy4=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -46, + "top": -286, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFUmNdyj9pAtFk=", + "_parent": { + "$ref": "AAAAAAFUmNdyjto3Jy4=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -46, + "top": -286, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 480, + "top": 400, + "width": 167, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUmNdyjto42rU=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFUmNdyjto9J7o=" + }, + "operationCompartment": { + "$ref": "AAAAAAFUmNdyjto+23Y=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFUmNdyj9o/7Mk=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFUmNdyj9pAtFk=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFUmNjw3d8eD54=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298aBP0=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNjw3d8fv8Q=", + "_parent": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298aBP0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 488, + "top": 296, + "width": 121.03076171875, + "height": 13, + "autoResize": false, + "alpha": -1.5565114726115359, + "distance": 70.00714249274856, + "hostEdge": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "edgePosition": 1, + "underline": false, + "text": "+imageDownloader", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNjw3d8gCZ4=", + "_parent": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298aBP0=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 449, + "top": 297, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNjw3d8hrFY=", + "_parent": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298aBP0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 493, + "top": 298, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNjw3t8iKUQ=", + "_parent": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298bVKc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 454, + "top": 312, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNjw3t8jrtE=", + "_parent": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298bVKc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 451, + "top": 326, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNjw3t8kP7I=", + "_parent": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298bVKc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 458, + "top": 285, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNjw3t8lsTA=", + "_parent": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298cZas=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 464, + "top": 274, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNjw3t8mhPI=", + "_parent": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298cZas=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 450, + "top": 277, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmNjw3t8nrxk=", + "_parent": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298cZas=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 491, + "top": 270, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFUmNjw3t8obIo=", + "_parent": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298bVKc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 504, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFUmNjw3t8plxw=", + "_parent": { + "$ref": "AAAAAAFUmNjw3d8eD54=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298cZas=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 504, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmMuDNcmaKIo=" + }, + "tail": { + "$ref": "AAAAAAFky2+2+WTD+rs=" + }, + "lineStyle": 0, + "points": "480:304;479:304;479:255", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFUmNjw3d8fv8Q=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFUmNjw3d8gCZ4=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmNjw3d8hrFY=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFUmNjw3t8iKUQ=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFUmNjw3t8jrtE=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFUmNjw3t8kP7I=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFUmNjw3t8lsTA=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFUmNjw3t8mhPI=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFUmNjw3t8nrxk=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFUmNjw3t8obIo=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFUmNjw3t8plxw=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFUmN7w++U0Wt4=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmN6ZSOUCaRM=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUmN7w++U1D3A=", + "_parent": { + "$ref": "AAAAAAFUmN7w++U0Wt4=" + }, + "model": { + "$ref": "AAAAAAFUmN6ZSOUCaRM=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUmN7w/OU2AsY=", + "_parent": { + "$ref": "AAAAAAFUmN7w++U1D3A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -536, + "top": -264, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmN7w/OU3+1Q=", + "_parent": { + "$ref": "AAAAAAFUmN7w++U1D3A=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 837, + "top": 143, + "width": 208, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageCombinedOperation", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmN7w/OU4h5k=", + "_parent": { + "$ref": "AAAAAAFUmN7w++U1D3A=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 837, + "top": 158, + "width": 208, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmN7w/OU5Fgw=", + "_parent": { + "$ref": "AAAAAAFUmN7w++U1D3A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -536, + "top": -264, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 832, + "top": 136, + "width": 218, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUmN7w/OU2AsY=" + }, + "nameLabel": { + "$ref": "AAAAAAFUmN7w/OU3+1Q=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUmN7w/OU4h5k=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmN7w/OU5Fgw=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFUmN7w/OU61Fs=", + "_parent": { + "$ref": "AAAAAAFUmN7w++U0Wt4=" + }, + "model": { + "$ref": "AAAAAAFUmN6ZSOUCaRM=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky13cPgMphao=", + "_parent": { + "$ref": "AAAAAAFUmN7w/OU61Fs=" + }, + "model": { + "$ref": "AAAAAAFky13cFAMXBnI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 821, + "top": 149, + "width": 260.7490234375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cacheOperation: SDWebImageOperation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky14V3wR03QQ=", + "_parent": { + "$ref": "AAAAAAFUmN7w/OU61Fs=" + }, + "model": { + "$ref": "AAAAAAFky14VtQRiZl8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 821, + "top": 164, + "width": 260.7490234375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+loaderOperation: SDWebImageOperation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 832, + "top": 176, + "width": 270.7490234375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFUmN7w/eU7uaA=", + "_parent": { + "$ref": "AAAAAAFUmN7w++U0Wt4=" + }, + "model": { + "$ref": "AAAAAAFUmN6ZSOUCaRM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 832, + "top": 214, + "width": 270.7490234375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFUmN7w/eU88NU=", + "_parent": { + "$ref": "AAAAAAFUmN7w++U0Wt4=" + }, + "model": { + "$ref": "AAAAAAFUmN6ZSOUCaRM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -316, + "top": -132, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFUmN7w/eU9h3Y=", + "_parent": { + "$ref": "AAAAAAFUmN7w++U0Wt4=" + }, + "model": { + "$ref": "AAAAAAFUmN6ZSOUCaRM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -316, + "top": -132, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 832, + "top": 136, + "width": 218, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUmN7w++U1D3A=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFUmN7w/OU61Fs=" + }, + "operationCompartment": { + "$ref": "AAAAAAFUmN7w/eU7uaA=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFUmN7w/eU88NU=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFUmN7w/eU9h3Y=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFUmN83d+YgNU8=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmN83d+YhTFs=", + "_parent": { + "$ref": "AAAAAAFUmN83d+YgNU8=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1076, + "top": 133, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFUmN83d+YgNU8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmN83eOYiOlg=", + "_parent": { + "$ref": "AAAAAAFUmN83d+YgNU8=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1076, + "top": 118, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUmN83d+YgNU8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmN83eOYjmKI=", + "_parent": { + "$ref": "AAAAAAFUmN83d+YgNU8=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1076, + "top": 163, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFUmN83d+YgNU8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmNWcUNb3p+o=" + }, + "tail": { + "$ref": "AAAAAAFUmN7w++U0Wt4=" + }, + "lineStyle": 0, + "points": "1049:154;1104:154", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFUmN83d+YhTFs=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFUmN83eOYiOlg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmN83eOYjmKI=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFUmOQ29O44VzA=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUmOQ29O45aDI=", + "_parent": { + "$ref": "AAAAAAFUmOQ29O44VzA=" + }, + "model": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUmOQ29O46cUE=", + "_parent": { + "$ref": "AAAAAAFUmOQ29O45aDI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 568, + "top": 62, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmOQ29e47Da4=", + "_parent": { + "$ref": "AAAAAAFUmOQ29O45aDI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1149, + "top": 335, + "width": 218, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloaderOperation", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmOQ29e48kII=", + "_parent": { + "$ref": "AAAAAAFUmOQ29O45aDI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1149, + "top": 350, + "width": 218, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmOQ29e490xI=", + "_parent": { + "$ref": "AAAAAAFUmOQ29O45aDI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 568, + "top": 62, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1144, + "top": 328, + "width": 228, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUmOQ29O46cUE=" + }, + "nameLabel": { + "$ref": "AAAAAAFUmOQ29e47Da4=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUmOQ29e48kII=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmOQ29e490xI=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFUmOQ29e4+IBw=", + "_parent": { + "$ref": "AAAAAAFUmOQ29O44VzA=" + }, + "model": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFUmO2Trw0FylY=", + "_parent": { + "$ref": "AAAAAAFUmOQ29e4+IBw=" + }, + "model": { + "$ref": "AAAAAAFUmO2TmQzzs/g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1205, + "top": 181, + "width": 268.2138671875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+options: SDWebImageDownloaderOptions", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky4mA5L8X1lE=", + "_parent": { + "$ref": "AAAAAAFUmOQ29e4+IBw=" + }, + "model": { + "$ref": "AAAAAAFky4mAub8FNII=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1205, + "top": 196, + "width": 268.2138671875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+context", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1144, + "top": 368, + "width": 278.2138671875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFUmOQ29e4/KXY=", + "_parent": { + "$ref": "AAAAAAFUmOQ29O44VzA=" + }, + "model": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1144, + "top": 406, + "width": 278.2138671875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFUmOQ29u5AeKo=", + "_parent": { + "$ref": "AAAAAAFUmOQ29O44VzA=" + }, + "model": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 284, + "top": 31, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFUmOQ29u5B6fk=", + "_parent": { + "$ref": "AAAAAAFUmOQ29O44VzA=" + }, + "model": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 284, + "top": 31, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1144, + "top": 328, + "width": 228, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUmOQ29O45aDI=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFUmOQ29e4+IBw=" + }, + "operationCompartment": { + "$ref": "AAAAAAFUmOQ29e4/KXY=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFUmOQ29u5AeKo=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFUmOQ29u5B6fk=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFUmORm3fAxc2k=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmORm3vAy30U=", + "_parent": { + "$ref": "AAAAAAFUmORm3fAxc2k=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1161, + "top": 247, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFUmORm3fAxc2k=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmORm3vAz3FI=", + "_parent": { + "$ref": "AAAAAAFUmORm3fAxc2k=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1146, + "top": 247, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUmORm3fAxc2k=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUmORm3vA0d1I=", + "_parent": { + "$ref": "AAAAAAFUmORm3fAxc2k=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1190, + "top": 248, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFUmORm3fAxc2k=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmNWcUNb3p+o=" + }, + "tail": { + "$ref": "AAAAAAFUmOQ29O44VzA=" + }, + "lineStyle": 0, + "points": "1176:328;1176:180", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFUmORm3vAy30U=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFUmORm3vAz3FI=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmORm3vA0d1I=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFUmPnxoSwmlwM=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUmPnxoSwnGWc=", + "_parent": { + "$ref": "AAAAAAFUmPnxoSwmlwM=" + }, + "model": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUmPnxoiwoWyI=", + "_parent": { + "$ref": "AAAAAAFUmPnxoSwnGWc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -342, + "top": -1874, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmPnxoiwp/Pc=", + "_parent": { + "$ref": "AAAAAAFUmPnxoSwnGWc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 573, + "top": 23, + "width": 195, + "height": 13, + "autoResize": false, + "underline": false, + "text": "MKAnnotationView (WebCache)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmPnxoiwqc/8=", + "_parent": { + "$ref": "AAAAAAFUmPnxoSwnGWc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 573, + "top": 38, + "width": 195, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmPnxoiwr8yc=", + "_parent": { + "$ref": "AAAAAAFUmPnxoSwnGWc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -342, + "top": -1874, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 568, + "top": 16, + "width": 205, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUmPnxoiwoWyI=" + }, + "nameLabel": { + "$ref": "AAAAAAFUmPnxoiwp/Pc=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUmPnxoiwqc/8=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmPnxoiwr8yc=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFUmPnxoiwsEx4=", + "_parent": { + "$ref": "AAAAAAFUmPnxoSwmlwM=" + }, + "model": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 568, + "top": 56, + "width": 220.23828125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFUmPnxoiwt1Co=", + "_parent": { + "$ref": "AAAAAAFUmPnxoSwmlwM=" + }, + "model": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmPnxsyxbMFU=", + "_parent": { + "$ref": "AAAAAAFUmPnxoiwt1Co=" + }, + "model": { + "$ref": "AAAAAAFUmPndIiv0KoI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 557, + "top": 71, + "width": 210.23828125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sd_setImageWithURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 568, + "top": 66, + "width": 220.23828125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFUmPnxoywuDz4=", + "_parent": { + "$ref": "AAAAAAFUmPnxoSwmlwM=" + }, + "model": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -171, + "top": -937, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFUmPnxoywvM6Y=", + "_parent": { + "$ref": "AAAAAAFUmPnxoSwmlwM=" + }, + "model": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -171, + "top": -937, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 568, + "top": 16, + "width": 205, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUmPnxoSwnGWc=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFUmPnxoiwsEx4=" + }, + "operationCompartment": { + "$ref": "AAAAAAFUmPnxoiwt1Co=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFUmPnxoywuDz4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFUmPnxoywvM6Y=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFUmPsPJi0J5Fw=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUmPsPJi0KI5E=", + "_parent": { + "$ref": "AAAAAAFUmPsPJi0J5Fw=" + }, + "model": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUmPsPJy0L8J0=", + "_parent": { + "$ref": "AAAAAAFUmPsPJi0KI5E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1268, + "top": -1920, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmPsPJy0MwGc=", + "_parent": { + "$ref": "AAAAAAFUmPsPJi0KI5E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 429, + "top": 23, + "width": 131, + "height": 13, + "autoResize": false, + "underline": false, + "text": "UIButton (WebCache)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmPsPJy0Nux0=", + "_parent": { + "$ref": "AAAAAAFUmPsPJi0KI5E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 429, + "top": 38, + "width": 131, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmPsPJy0OJqI=", + "_parent": { + "$ref": "AAAAAAFUmPsPJi0KI5E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1268, + "top": -1920, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 424, + "top": 16, + "width": 141, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUmPsPJy0L8J0=" + }, + "nameLabel": { + "$ref": "AAAAAAFUmPsPJy0MwGc=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUmPsPJy0Nux0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmPsPJy0OJqI=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFUmPsPKC0PxY4=", + "_parent": { + "$ref": "AAAAAAFUmPsPJi0J5Fw=" + }, + "model": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 424, + "top": 56, + "width": 156.2119140625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFUmPsPKC0QR5M=", + "_parent": { + "$ref": "AAAAAAFUmPsPJi0J5Fw=" + }, + "model": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmPsYuS19oBM=", + "_parent": { + "$ref": "AAAAAAFUmPsPKC0QR5M=" + }, + "model": { + "$ref": "AAAAAAFUmPsYkS1rEno=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 429, + "top": 71, + "width": 146.2119140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sd_setImageWithURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 424, + "top": 66, + "width": 156.2119140625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFUmPsPKC0RGsg=", + "_parent": { + "$ref": "AAAAAAFUmPsPJi0J5Fw=" + }, + "model": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -634, + "top": -960, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFUmPsPKC0Ssb0=", + "_parent": { + "$ref": "AAAAAAFUmPsPJi0J5Fw=" + }, + "model": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -634, + "top": -960, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 424, + "top": 16, + "width": 141, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUmPsPJi0KI5E=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFUmPsPKC0PxY4=" + }, + "operationCompartment": { + "$ref": "AAAAAAFUmPsPKC0QR5M=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFUmPsPKC0RGsg=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFUmPsPKC0Ssb0=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFUmPubFi7kzSY=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUmPubFi7ldgA=", + "_parent": { + "$ref": "AAAAAAFUmPubFi7kzSY=" + }, + "model": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUmPubFy7m7zM=", + "_parent": { + "$ref": "AAAAAAFUmPubFi7ldgA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1150, + "top": -1918, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmPubFy7n6Dk=", + "_parent": { + "$ref": "AAAAAAFUmPubFi7ldgA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 23, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "UIImageView (WebCache)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmPubFy7oD0o=", + "_parent": { + "$ref": "AAAAAAFUmPubFi7ldgA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 38, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUmPubFy7pkco=", + "_parent": { + "$ref": "AAAAAAFUmPubFi7ldgA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1150, + "top": -1918, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 16, + "width": 168, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUmPubFy7m7zM=" + }, + "nameLabel": { + "$ref": "AAAAAAFUmPubFy7n6Dk=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUmPubFy7oD0o=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUmPubFy7pkco=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFUmPubFy7qR80=", + "_parent": { + "$ref": "AAAAAAFUmPubFi7kzSY=" + }, + "model": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 56, + "width": 179.64501953125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFUmPubGC7rOFM=", + "_parent": { + "$ref": "AAAAAAFUmPubFi7kzSY=" + }, + "model": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFUmPubKC8Z6Qs=", + "_parent": { + "$ref": "AAAAAAFUmPubGC7rOFM=" + }, + "model": { + "$ref": "AAAAAAFUmPuK4C6yWrI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 71, + "width": 169.64501953125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sd_setImageWithURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 66, + "width": 179.64501953125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFUmPubGC7scHg=", + "_parent": { + "$ref": "AAAAAAFUmPubFi7kzSY=" + }, + "model": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -575, + "top": -967, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFUmPubGC7t9Sw=", + "_parent": { + "$ref": "AAAAAAFUmPubFi7kzSY=" + }, + "model": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -575, + "top": -967, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 16, + "width": 168, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUmPubFi7ldgA=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFUmPubFy7qR80=" + }, + "operationCompartment": { + "$ref": "AAAAAAFUmPubGC7rOFM=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFUmPubGC7scHg=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFUmPubGC7t9Sw=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFUv153Vizx38c=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmOrfAwPdh8M=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv153VizyEA0=", + "_parent": { + "$ref": "AAAAAAFUv153Vizx38c=" + }, + "model": { + "$ref": "AAAAAAFUmOrfAwPdh8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 925, + "top": 228, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFUv153Vizx38c=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv153Vizz7lI=", + "_parent": { + "$ref": "AAAAAAFUv153Vizx38c=" + }, + "model": { + "$ref": "AAAAAAFUmOrfAwPdh8M=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 910, + "top": 228, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUv153Vizx38c=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv153Viz0D4s=", + "_parent": { + "$ref": "AAAAAAFUv153Vizx38c=" + }, + "model": { + "$ref": "AAAAAAFUmOrfAwPdh8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 954, + "top": 229, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFUv153Vizx38c=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmN7w++U0Wt4=" + }, + "tail": { + "$ref": "AAAAAAFUmMuDNcmaKIo=" + }, + "lineStyle": 0, + "points": "521:235;940:235;940:175", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFUv153VizyEA0=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFUv153Vizz7lI=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUv153Viz0D4s=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFUv164Jiz16MQ=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmOrfAwPdh8M=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv164Jiz2vwg=", + "_parent": { + "$ref": "AAAAAAFUv164Jiz16MQ=" + }, + "model": { + "$ref": "AAAAAAFUmOrfAwPdh8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1242, + "top": 412, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFUv164Jiz16MQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv164Jiz32u4=", + "_parent": { + "$ref": "AAAAAAFUv164Jiz16MQ=" + }, + "model": { + "$ref": "AAAAAAFUmOrfAwPdh8M=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1227, + "top": 412, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFUv164Jiz16MQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv164Jiz4K3E=", + "_parent": { + "$ref": "AAAAAAFUv164Jiz16MQ=" + }, + "model": { + "$ref": "AAAAAAFUmOrfAwPdh8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1271, + "top": 413, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFUv164Jiz16MQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmOQ29O44VzA=" + }, + "tail": { + "$ref": "AAAAAAFUmNdyjto3Jy4=" + }, + "lineStyle": 0, + "points": "646:419;1257:419;1257:367", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFUv164Jiz2vwg=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFUv164Jiz32u4=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUv164Jiz4K3E=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFXmsqnFRq0kTA=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFXmsqnFhq1c88=", + "_parent": { + "$ref": "AAAAAAFXmsqnFRq0kTA=" + }, + "model": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFXmsqnFhq2cuo=", + "_parent": { + "$ref": "AAAAAAFXmsqnFhq1c88=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 528, + "top": -428, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmsqnFhq3kPQ=", + "_parent": { + "$ref": "AAAAAAFXmsqnFhq1c88=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 365, + "top": 111, + "width": 120, + "height": 13, + "autoResize": false, + "underline": false, + "text": "UIView (WebCache)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmsqnFhq4uH4=", + "_parent": { + "$ref": "AAAAAAFXmsqnFhq1c88=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 365, + "top": 126, + "width": 120, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmsqnFxq5Aig=", + "_parent": { + "$ref": "AAAAAAFXmsqnFhq1c88=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 528, + "top": -428, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 360, + "top": 104, + "width": 130, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFXmsqnFhq2cuo=" + }, + "nameLabel": { + "$ref": "AAAAAAFXmsqnFhq3kPQ=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFXmsqnFhq4uH4=" + }, + "propertyLabel": { + "$ref": "AAAAAAFXmsqnFxq5Aig=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFXmsqnFxq6HJk=", + "_parent": { + "$ref": "AAAAAAFXmsqnFRq0kTA=" + }, + "model": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 360, + "top": 144, + "width": 204.84130859375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFXmsqnFxq7RZM=", + "_parent": { + "$ref": "AAAAAAFXmsqnFRq0kTA=" + }, + "model": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFXmsqnLRr1d7w=", + "_parent": { + "$ref": "AAAAAAFXmsqnFxq7RZM=" + }, + "model": { + "$ref": "AAAAAAFXmsqK3idvzv0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 349, + "top": 127, + "width": 194.84130859375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sd_internalSetImageWithURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 360, + "top": 154, + "width": 204.84130859375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFXmsqnGBq8Kaw=", + "_parent": { + "$ref": "AAAAAAFXmsqnFRq0kTA=" + }, + "model": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 264, + "top": -214, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFXmsqnGBq9kZI=", + "_parent": { + "$ref": "AAAAAAFXmsqnFRq0kTA=" + }, + "model": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 264, + "top": -214, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 360, + "top": 104, + "width": 130, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFXmsqnFhq1c88=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFXmsqnFxq6HJk=" + }, + "operationCompartment": { + "$ref": "AAAAAAFXmsqnFxq7RZM=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFXmsqnGBq8Kaw=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFXmsqnGBq9kZI=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFXmuWYrYcCa9s=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFXmuWYrocDzj4=", + "_parent": { + "$ref": "AAAAAAFXmuWYrYcCa9s=" + }, + "model": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFXmuWYrocEdZA=", + "_parent": { + "$ref": "AAAAAAFXmuWYrocDzj4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1014, + "top": -936, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmuWYrocFtRE=", + "_parent": { + "$ref": "AAAAAAFXmuWYrocDzj4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 853, + "top": 271, + "width": 183, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloadToken", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmuWYrocGczg=", + "_parent": { + "$ref": "AAAAAAFXmuWYrocDzj4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 853, + "top": 286, + "width": 183, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmuWYrocHYrQ=", + "_parent": { + "$ref": "AAAAAAFXmuWYrocDzj4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1014, + "top": -936, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 848, + "top": 264, + "width": 193, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFXmuWYrocEdZA=" + }, + "nameLabel": { + "$ref": "AAAAAAFXmuWYrocFtRE=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFXmuWYrocGczg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFXmuWYrocHYrQ=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFXmuWYrocIclQ=", + "_parent": { + "$ref": "AAAAAAFXmuWYrYcCa9s=" + }, + "model": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFXmuY464jBWIE=", + "_parent": { + "$ref": "AAAAAAFXmuWYrocIclQ=" + }, + "model": { + "$ref": "AAAAAAFXmuY4yIivPbY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 829, + "top": 53, + "width": 195.27294921875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+url", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFXmuZProl8gys=", + "_parent": { + "$ref": "AAAAAAFXmuWYrocIclQ=" + }, + "model": { + "$ref": "AAAAAAFXmuZPjolqbRg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 829, + "top": 68, + "width": 195.27294921875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+request", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky24w5WMZnZo=", + "_parent": { + "$ref": "AAAAAAFXmuWYrocIclQ=" + }, + "model": { + "$ref": "AAAAAAFky24wtWMHKQ0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 829, + "top": 83, + "width": 195.27294921875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+response", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 848, + "top": 304, + "width": 205.27294921875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFXmuWYr4cJuVk=", + "_parent": { + "$ref": "AAAAAAFXmuWYrYcCa9s=" + }, + "model": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 848, + "top": 357, + "width": 205.27294921875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFXmuWYr4cKCZk=", + "_parent": { + "$ref": "AAAAAAFXmuWYrYcCa9s=" + }, + "model": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -579, + "top": -468, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFXmuWYr4cLRac=", + "_parent": { + "$ref": "AAAAAAFXmuWYrYcCa9s=" + }, + "model": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -579, + "top": -468, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 848, + "top": 264, + "width": 193, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFXmuWYrocDzj4=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFXmuWYrocIclQ=" + }, + "operationCompartment": { + "$ref": "AAAAAAFXmuWYr4cJuVk=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFXmuWYr4cKCZk=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFXmuWYr4cLRac=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFXmuZ1b4oYynI=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFXmuZ1booW7c8=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmuZ1b4oZevc=", + "_parent": { + "$ref": "AAAAAAFXmuZ1b4oYynI=" + }, + "model": { + "$ref": "AAAAAAFXmuZ1booW7c8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 929, + "top": 412, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFXmuZ1b4oYynI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmuZ1b4oaUQk=", + "_parent": { + "$ref": "AAAAAAFXmuZ1b4oYynI=" + }, + "model": { + "$ref": "AAAAAAFXmuZ1booW7c8=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 914, + "top": 412, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFXmuZ1b4oYynI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmuZ1b4obVbI=", + "_parent": { + "$ref": "AAAAAAFXmuZ1b4oYynI=" + }, + "model": { + "$ref": "AAAAAAFXmuZ1booW7c8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 959, + "top": 413, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFXmuZ1b4oYynI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFXmuWYrYcCa9s=" + }, + "tail": { + "$ref": "AAAAAAFUmNdyjto3Jy4=" + }, + "lineStyle": 0, + "points": "646:419;944:419;944:303", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFXmuZ1b4oZevc=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFXmuZ1b4oaUQk=" + }, + "propertyLabel": { + "$ref": "AAAAAAFXmuZ1b4obVbI=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFXmwHlQZfcwhE=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFXmwHlQpfdaR4=", + "_parent": { + "$ref": "AAAAAAFXmwHlQZfcwhE=" + }, + "model": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFXmwHlQpfeXHo=", + "_parent": { + "$ref": "AAAAAAFXmwHlQpfdaR4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -446, + "top": -412, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmwHlQpff/Yk=", + "_parent": { + "$ref": "AAAAAAFXmwHlQpfdaR4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 455, + "width": 135, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCacheConfig", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmwHlQpfgKbE=", + "_parent": { + "$ref": "AAAAAAFXmwHlQpfdaR4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 470, + "width": 135, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmwHlQ5fhKcI=", + "_parent": { + "$ref": "AAAAAAFXmwHlQpfdaR4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -446, + "top": -412, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 448, + "width": 145, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFXmwHlQpfeXHo=" + }, + "nameLabel": { + "$ref": "AAAAAAFXmwHlQpff/Yk=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFXmwHlQpfgKbE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFXmwHlQ5fhKcI=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFXmwHlQ5firCI=", + "_parent": { + "$ref": "AAAAAAFXmwHlQZfcwhE=" + }, + "model": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFXmwKSlp0N8TY=", + "_parent": { + "$ref": "AAAAAAFXmwHlQ5firCI=" + }, + "model": { + "$ref": "AAAAAAFUmPBKVhghKWk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -91, + "width": 195.48876953125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+shouldDecompressImages", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFXmwK3GZ1cp9k=", + "_parent": { + "$ref": "AAAAAAFXmwHlQ5firCI=" + }, + "model": { + "$ref": "AAAAAAFUmPBxrhjcaQc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -76, + "width": 195.48876953125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+shouldDisableiCloud", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFXmwLWr52r7TI=", + "_parent": { + "$ref": "AAAAAAFXmwHlQ5firCI=" + }, + "model": { + "$ref": "AAAAAAFUmPCLlRmXEPs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -61, + "width": 195.48876953125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+shouldCacheImagesInMemory", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFXmwL16Z364rc=", + "_parent": { + "$ref": "AAAAAAFXmwHlQ5firCI=" + }, + "model": { + "$ref": "AAAAAAFUmPD+pRvI9sU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -46, + "width": 195.48876953125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+maxCacheAge", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFXmwMPqZ5JH+8=", + "_parent": { + "$ref": "AAAAAAFXmwHlQ5firCI=" + }, + "model": { + "$ref": "AAAAAAFUmPEdRRyDmKo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -31, + "width": 195.48876953125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+maxCacheSize", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 488, + "width": 205.48876953125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFXmwHlQ5fjsoY=", + "_parent": { + "$ref": "AAAAAAFXmwHlQZfcwhE=" + }, + "model": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 571, + "width": 205.48876953125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFXmwHlQ5fk/sQ=", + "_parent": { + "$ref": "AAAAAAFXmwHlQZfcwhE=" + }, + "model": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -215, + "top": -238, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFXmwHlRJflFgo=", + "_parent": { + "$ref": "AAAAAAFXmwHlQZfcwhE=" + }, + "model": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -215, + "top": -238, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 448, + "width": 145, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFXmwHlQpfdaR4=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFXmwHlQ5firCI=" + }, + "operationCompartment": { + "$ref": "AAAAAAFXmwHlQ5fjsoY=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFXmwHlQ5fk/sQ=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFXmwHlRJflFgo=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFXmwYAOLO7iOA=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmwYAOLO8LcI=", + "_parent": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 217, + "top": 436, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmwYAOLO9Sqw=", + "_parent": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 202, + "top": 436, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmwYAOLO+C+4=", + "_parent": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 246, + "top": 437, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmwYAOLO/nAA=", + "_parent": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 177, + "top": 446, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmwYAOLPAH1M=", + "_parent": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 180, + "top": 432, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmwYAObPBDvI=", + "_parent": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 173, + "top": 473, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmwYAObPC0G4=", + "_parent": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 247, + "top": 398, + "width": 46.490234375, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "edgePosition": 0, + "underline": false, + "text": "+config", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmwYAObPDf9g=", + "_parent": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 267, + "top": 384, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmwYAObPEkvU=", + "_parent": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 274, + "top": 425, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFXmwYAObPFxXo=", + "_parent": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 264, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFXmwYAObPG0jM=", + "_parent": { + "$ref": "AAAAAAFXmwYAOLO7iOA=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 264, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmNdXmNnpp1I=" + }, + "tail": { + "$ref": "AAAAAAFXmwHlQZfcwhE=" + }, + "lineStyle": 0, + "points": "152:467;232:467;232:419;296:419", + "stereotypeDisplay": "none", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFXmwYAOLO8LcI=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFXmwYAOLO9Sqw=" + }, + "propertyLabel": { + "$ref": "AAAAAAFXmwYAOLO+C+4=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFXmwYAOLO/nAA=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFXmwYAOLPAH1M=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFXmwYAObPBDvI=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFXmwYAObPC0G4=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFXmwYAObPDf9g=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFXmwYAObPEkvU=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFXmwYAObPFxXo=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFXmwYAObPG0jM=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFXmweIrMVi0w8=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFXmweIrcVjTI0=", + "_parent": { + "$ref": "AAAAAAFXmweIrMVi0w8=" + }, + "model": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFXmweIrcVkV0Y=", + "_parent": { + "$ref": "AAAAAAFXmweIrcVjTI0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1197, + "top": 221, + "width": 228, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmweIrcVlkN4=", + "_parent": { + "$ref": "AAAAAAFXmweIrcVjTI0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1197, + "top": 236, + "width": 228, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloaderOperation", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmweIrcVmjnM=", + "_parent": { + "$ref": "AAAAAAFXmweIrcVjTI0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1197, + "top": 251, + "width": 228, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmweIrcVnBvc=", + "_parent": { + "$ref": "AAAAAAFXmweIrcVjTI0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -818, + "top": -96, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1192, + "top": 216, + "width": 238, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFXmweIrcVkV0Y=" + }, + "nameLabel": { + "$ref": "AAAAAAFXmweIrcVlkN4=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFXmweIrcVmjnM=" + }, + "propertyLabel": { + "$ref": "AAAAAAFXmweIrcVnBvc=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFXmweIrcVoTE8=", + "_parent": { + "$ref": "AAAAAAFXmweIrMVi0w8=" + }, + "model": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -409, + "top": -48, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFXmweIrsVp1OA=", + "_parent": { + "$ref": "AAAAAAFXmweIrMVi0w8=" + }, + "model": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky4En/pocwIA=", + "_parent": { + "$ref": "AAAAAAFXmweIrsVp1OA=" + }, + "model": { + "$ref": "AAAAAAFky4EnyJoHXgk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1285, + "top": 186, + "width": 290.3798828125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(request, session, options, context)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky4L4a6GBnH8=", + "_parent": { + "$ref": "AAAAAAFXmweIrsVp1OA=" + }, + "model": { + "$ref": "AAAAAAFky4L4L6FsOVg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1285, + "top": 201, + "width": 290.3798828125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+addHandlers(progressBlock, completedBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky4PUHaQz/Jg=", + "_parent": { + "$ref": "AAAAAAFXmweIrsVp1OA=" + }, + "model": { + "$ref": "AAAAAAFky4PT6qQes1w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1285, + "top": 216, + "width": 290.3798828125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+credential(): URLCredential", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky4QsgqZAlFw=", + "_parent": { + "$ref": "AAAAAAFXmweIrsVp1OA=" + }, + "model": { + "$ref": "AAAAAAFky4QsQ6YrSFU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1285, + "top": 231, + "width": 290.3798828125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+setCredential(value)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky4SFdqgWN+s=", + "_parent": { + "$ref": "AAAAAAFXmweIrsVp1OA=" + }, + "model": { + "$ref": "AAAAAAFky4SFRKgB5qs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1285, + "top": 246, + "width": 290.3798828125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cancel(token): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky4UElKr/4qk=", + "_parent": { + "$ref": "AAAAAAFXmweIrsVp1OA=" + }, + "model": { + "$ref": "AAAAAAFky4UEV6rqaoE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1285, + "top": 261, + "width": 290.3798828125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+request()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky4U4/6xKiHE=", + "_parent": { + "$ref": "AAAAAAFXmweIrsVp1OA=" + }, + "model": { + "$ref": "AAAAAAFky4U4wKw1It0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1285, + "top": 276, + "width": 290.3798828125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+response()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky4VpZq2VJZI=", + "_parent": { + "$ref": "AAAAAAFXmweIrsVp1OA=" + }, + "model": { + "$ref": "AAAAAAFky4VpKK2AUTU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1285, + "top": 291, + "width": 290.3798828125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+dataTask(): URLSessionTask", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1192, + "top": 269, + "width": 300.3798828125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFXmweIrsVq3iY=", + "_parent": { + "$ref": "AAAAAAFXmweIrMVi0w8=" + }, + "model": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -409, + "top": -48, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFXmweIrsVr8cA=", + "_parent": { + "$ref": "AAAAAAFXmweIrMVi0w8=" + }, + "model": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -409, + "top": -48, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1192, + "top": 216, + "width": 262, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFXmweIrcVjTI0=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFXmweIrcVoTE8=" + }, + "operationCompartment": { + "$ref": "AAAAAAFXmweIrsVp1OA=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFXmweIrsVq3iY=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFXmweIrsVr8cA=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFXmwgWISehNBw=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmwgWIieiiIY=", + "_parent": { + "$ref": "AAAAAAFXmwgWISehNBw=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1289, + "top": 291, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFXmwgWISehNBw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmwgWIiej800=", + "_parent": { + "$ref": "AAAAAAFXmwgWISehNBw=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1274, + "top": 291, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFXmwgWISehNBw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmwgWIieksT0=", + "_parent": { + "$ref": "AAAAAAFXmwgWISehNBw=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1318, + "top": 292, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFXmwgWISehNBw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFXmweIrMVi0w8=" + }, + "tail": { + "$ref": "AAAAAAFUmOQ29O44VzA=" + }, + "lineStyle": 0, + "points": "1304:328;1304:268", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFXmwgWIieiiIY=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFXmwgWIiej800=" + }, + "propertyLabel": { + "$ref": "AAAAAAFXmwgWIieksT0=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFfKtnKU+Dd+kU=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFfKtnKU+DeJcg=", + "_parent": { + "$ref": "AAAAAAFfKtnKU+Dd+kU=" + }, + "model": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFfKtnKU+DfDpA=", + "_parent": { + "$ref": "AAAAAAFfKtnKU+DeJcg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 709, + "top": 725, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKtnKVODgfxk=", + "_parent": { + "$ref": "AAAAAAFfKtnKU+DeJcg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 709, + "top": 740, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKtnKVODhG4g=", + "_parent": { + "$ref": "AAAAAAFfKtnKU+DeJcg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 709, + "top": 755, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKtnKVODiSfg=", + "_parent": { + "$ref": "AAAAAAFfKtnKU+DeJcg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -692, + "top": -726, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 704, + "top": 720, + "width": 138, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFfKtnKU+DfDpA=" + }, + "nameLabel": { + "$ref": "AAAAAAFfKtnKVODgfxk=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFfKtnKVODhG4g=" + }, + "propertyLabel": { + "$ref": "AAAAAAFfKtnKVODiSfg=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFfKtnKVODj1qU=", + "_parent": { + "$ref": "AAAAAAFfKtnKU+Dd+kU=" + }, + "model": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -346, + "top": -363, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFfKtnKVODkLCQ=", + "_parent": { + "$ref": "AAAAAAFfKtnKU+Dd+kU=" + }, + "model": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFfKtnKa+EVl+g=", + "_parent": { + "$ref": "AAAAAAFfKtnKVODkLCQ=" + }, + "model": { + "$ref": "AAAAAAFfKtg9W998WOc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 493, + "top": -118, + "width": 275.28515625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+canDecode(data): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFfKtrKTuQEyI4=", + "_parent": { + "$ref": "AAAAAAFfKtnKVODkLCQ=" + }, + "model": { + "$ref": "AAAAAAFfKtrKNePvsF8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 493, + "top": -103, + "width": 275.28515625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+decodedImage(data, options): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFfKuUPd+7DPiQ=", + "_parent": { + "$ref": "AAAAAAFfKtnKVODkLCQ=" + }, + "model": { + "$ref": "AAAAAAFfKuUPYO6usi8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 493, + "top": -88, + "width": 275.28515625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+canEncode(format): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFfKuW6ufDe+NQ=", + "_parent": { + "$ref": "AAAAAAFfKtnKVODkLCQ=" + }, + "model": { + "$ref": "AAAAAAFfKuW6ofDJluc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 493, + "top": -73, + "width": 275.28515625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+encodedData(image, format, options): Data", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 704, + "top": 773, + "width": 285.28515625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFfKtnKVeDl8X0=", + "_parent": { + "$ref": "AAAAAAFfKtnKU+Dd+kU=" + }, + "model": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -346, + "top": -363, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFfKtnKVeDmN6s=", + "_parent": { + "$ref": "AAAAAAFfKtnKU+Dd+kU=" + }, + "model": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -346, + "top": -363, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 704, + "top": 720, + "width": 162, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFfKtnKU+DeJcg=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFfKtnKVODj1qU=" + }, + "operationCompartment": { + "$ref": "AAAAAAFfKtnKVODkLCQ=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFfKtnKVeDl8X0=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFfKtnKVeDmN6s=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFfKucZUPTSZzA=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFfKucZUPTTeR0=", + "_parent": { + "$ref": "AAAAAAFfKucZUPTSZzA=" + }, + "model": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFfKucZUPTUC8I=", + "_parent": { + "$ref": "AAAAAAFfKucZUPTTeR0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 589, + "top": 861, + "width": 177, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKucZUfTVZEc=", + "_parent": { + "$ref": "AAAAAAFfKucZUPTTeR0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 589, + "top": 876, + "width": 177, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDProgressiveImageCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKucZUfTWsy4=", + "_parent": { + "$ref": "AAAAAAFfKucZUPTTeR0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 589, + "top": 891, + "width": 177, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKucZUfTXwmM=", + "_parent": { + "$ref": "AAAAAAFfKucZUPTTeR0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -740, + "top": -868, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 584, + "top": 856, + "width": 187, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFfKucZUPTUC8I=" + }, + "nameLabel": { + "$ref": "AAAAAAFfKucZUfTVZEc=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFfKucZUfTWsy4=" + }, + "propertyLabel": { + "$ref": "AAAAAAFfKucZUfTXwmM=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFfKucZUfTYTng=", + "_parent": { + "$ref": "AAAAAAFfKucZUPTSZzA=" + }, + "model": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -290, + "top": -74, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFfKucZUfTZOas=", + "_parent": { + "$ref": "AAAAAAFfKucZUPTSZzA=" + }, + "model": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFfKudnOfb3mZ8=", + "_parent": { + "$ref": "AAAAAAFfKucZUfTZOas=" + }, + "model": { + "$ref": "AAAAAAFfKudnG/biyzM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 605, + "top": -62, + "width": 289.21826171875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+canIncrementalDecode(data): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky0IhCY8tixk=", + "_parent": { + "$ref": "AAAAAAFfKucZUfTZOas=" + }, + "model": { + "$ref": "AAAAAAFky0Ig1o8YU4s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 605, + "top": -47, + "width": 289.21826171875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(options)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky0LqNZEDNeQ=", + "_parent": { + "$ref": "AAAAAAFfKucZUfTZOas=" + }, + "model": { + "$ref": "AAAAAAFky0LqApDu034=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 605, + "top": -32, + "width": 289.21826171875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+updateIncrementalData(data, finished)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFfKugVGfmiAvo=", + "_parent": { + "$ref": "AAAAAAFfKucZUfTZOas=" + }, + "model": { + "$ref": "AAAAAAFfKugU/PmNPJQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 605, + "top": -17, + "width": 289.21826171875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+incrementalDecodedImage(options): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 584, + "top": 909, + "width": 299.21826171875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFfKucZUfTaXKw=", + "_parent": { + "$ref": "AAAAAAFfKucZUPTSZzA=" + }, + "model": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -290, + "top": -74, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFfKucZUvTb4UA=", + "_parent": { + "$ref": "AAAAAAFfKucZUPTSZzA=" + }, + "model": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -290, + "top": -74, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 584, + "top": 856, + "width": 211, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFfKucZUPTTeR0=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFfKucZUfTYTng=" + }, + "operationCompartment": { + "$ref": "AAAAAAFfKucZUfTZOas=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFfKucZUfTaXKw=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFfKucZUvTb4UA=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFfKulRr/y/5nQ=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFfKulRr/zAn18=", + "_parent": { + "$ref": "AAAAAAFfKulRr/y/5nQ=" + }, + "model": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFfKulRsPzB/EA=", + "_parent": { + "$ref": "AAAAAAFfKulRr/zAn18=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -186, + "top": -1020, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKulRsPzCgK8=", + "_parent": { + "$ref": "AAAAAAFfKulRr/zAn18=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 469, + "top": 735, + "width": 153, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCodersManager", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKulRsPzDkaQ=", + "_parent": { + "$ref": "AAAAAAFfKulRr/zAn18=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 469, + "top": 750, + "width": 153, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKulRsPzEzwU=", + "_parent": { + "$ref": "AAAAAAFfKulRr/zAn18=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -186, + "top": -1020, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 464, + "top": 728, + "width": 163, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFfKulRsPzB/EA=" + }, + "nameLabel": { + "$ref": "AAAAAAFfKulRsPzCgK8=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFfKulRsPzDkaQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFfKulRsPzEzwU=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFfKulRsPzF/IA=", + "_parent": { + "$ref": "AAAAAAFfKulRr/y/5nQ=" + }, + "model": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFfKvIM3iczUk4=", + "_parent": { + "$ref": "AAAAAAFfKulRsPzF/IA=" + }, + "model": { + "$ref": "AAAAAAFfKvIMwCceZuI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 301, + "top": -115, + "width": 199.98291015625, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedInstance", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFfKvJtpynJYTw=", + "_parent": { + "$ref": "AAAAAAFfKulRsPzF/IA=" + }, + "model": { + "$ref": "AAAAAAFfKvJtjym0wQE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 301, + "top": -100, + "width": 199.98291015625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+coders: Array ", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 464, + "top": 768, + "width": 209.98291015625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFfKulRsPzGZjg=", + "_parent": { + "$ref": "AAAAAAFfKulRr/y/5nQ=" + }, + "model": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFfKvJLEyjrAlw=", + "_parent": { + "$ref": "AAAAAAFfKulRsPzGZjg=" + }, + "model": { + "$ref": "AAAAAAFfKvJK9yjW40I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 301, + "top": -77, + "width": 199.98291015625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+add(coder)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFfKvPFlzM7d88=", + "_parent": { + "$ref": "AAAAAAFfKulRsPzGZjg=" + }, + "model": { + "$ref": "AAAAAAFfKvPFeTMmARs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 301, + "top": -62, + "width": 199.98291015625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+remove(coder)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 464, + "top": 806, + "width": 209.98291015625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFfKulRsfzHiZ8=", + "_parent": { + "$ref": "AAAAAAFfKulRr/y/5nQ=" + }, + "model": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -93, + "top": -510, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFfKulRsfzIWr8=", + "_parent": { + "$ref": "AAAAAAFfKulRr/y/5nQ=" + }, + "model": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -93, + "top": -510, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 464, + "top": 728, + "width": 163, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFfKulRr/zAn18=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFfKulRsPzF/IA=" + }, + "operationCompartment": { + "$ref": "AAAAAAFfKulRsPzGZjg=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFfKulRsfzHiZ8=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFfKulRsfzIWr8=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFfKumI8P16C6U=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKul3rf0/okM=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFfKumI8P17Zb0=", + "_parent": { + "$ref": "AAAAAAFfKumI8P16C6U=" + }, + "model": { + "$ref": "AAAAAAFfKul3rf0/okM=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFfKumI8P18+tw=", + "_parent": { + "$ref": "AAAAAAFfKumI8P17Zb0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 106, + "top": -754, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKumI8P19Lbk=", + "_parent": { + "$ref": "AAAAAAFfKumI8P17Zb0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 549, + "top": 1012, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageIOCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKumI8P1+6As=", + "_parent": { + "$ref": "AAAAAAFfKumI8P17Zb0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 549, + "top": 1027, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKumI8P1/Beo=", + "_parent": { + "$ref": "AAAAAAFfKumI8P17Zb0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 106, + "top": -754, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 544, + "top": 1005, + "width": 128, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFfKumI8P18+tw=" + }, + "nameLabel": { + "$ref": "AAAAAAFfKumI8P19Lbk=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFfKumI8P1+6As=" + }, + "propertyLabel": { + "$ref": "AAAAAAFfKumI8P1/Beo=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFfKumI8P2AZF0=", + "_parent": { + "$ref": "AAAAAAFfKumI8P16C6U=" + }, + "model": { + "$ref": "AAAAAAFfKul3rf0/okM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 544, + "top": 1045, + "width": 133.82373046875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFfKumI8P2B0+M=", + "_parent": { + "$ref": "AAAAAAFfKumI8P16C6U=" + }, + "model": { + "$ref": "AAAAAAFfKul3rf0/okM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 544, + "top": 1055, + "width": 133.82373046875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFfKumI8P2CWf4=", + "_parent": { + "$ref": "AAAAAAFfKumI8P16C6U=" + }, + "model": { + "$ref": "AAAAAAFfKul3rf0/okM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -371, + "top": -377, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFfKumI8P2DxlI=", + "_parent": { + "$ref": "AAAAAAFfKumI8P16C6U=" + }, + "model": { + "$ref": "AAAAAAFfKul3rf0/okM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -371, + "top": -377, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 544, + "top": 1005, + "width": 128, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFfKumI8P17Zb0=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFfKumI8P2AZF0=" + }, + "operationCompartment": { + "$ref": "AAAAAAFfKumI8P2B0+M=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFfKumI8P2CWf4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFfKumI8P2DxlI=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFfKumzBf41WYU=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFfKumzBv42z7s=", + "_parent": { + "$ref": "AAAAAAFfKumzBf41WYU=" + }, + "model": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFfKumzBv43q9A=", + "_parent": { + "$ref": "AAAAAAFfKumzBv42z7s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 154, + "top": -924, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKumzBv44A7s=", + "_parent": { + "$ref": "AAAAAAFfKumzBv42z7s=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 829, + "top": 1012, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageGIFCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKumzBv45dsM=", + "_parent": { + "$ref": "AAAAAAFfKumzBv42z7s=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 829, + "top": 1027, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKumzBv46Fe0=", + "_parent": { + "$ref": "AAAAAAFfKumzBv42z7s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 154, + "top": -924, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 824, + "top": 1005, + "width": 128, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFfKumzBv43q9A=" + }, + "nameLabel": { + "$ref": "AAAAAAFfKumzBv44A7s=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFfKumzBv45dsM=" + }, + "propertyLabel": { + "$ref": "AAAAAAFfKumzBv46Fe0=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFfKumzBv47Kuo=", + "_parent": { + "$ref": "AAAAAAFfKumzBf41WYU=" + }, + "model": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 824, + "top": 1045, + "width": 133.82373046875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFfKumzB/48Lsc=", + "_parent": { + "$ref": "AAAAAAFfKumzBf41WYU=" + }, + "model": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 824, + "top": 1055, + "width": 133.82373046875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFfKumzB/499l4=", + "_parent": { + "$ref": "AAAAAAFfKumzBf41WYU=" + }, + "model": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 93, + "top": -486, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFfKumzB/4+eKg=", + "_parent": { + "$ref": "AAAAAAFfKumzBf41WYU=" + }, + "model": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 93, + "top": -486, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 824, + "top": 1005, + "width": 128, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFfKumzBv42z7s=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFfKumzBv47Kuo=" + }, + "operationCompartment": { + "$ref": "AAAAAAFfKumzB/48Lsc=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFfKumzB/499l4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFfKumzB/4+eKg=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFfKunfeP7w4nM=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFfKunfeP7xxxs=", + "_parent": { + "$ref": "AAAAAAFfKunfeP7w4nM=" + }, + "model": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFfKunfeP7yLV4=", + "_parent": { + "$ref": "AAAAAAFfKunfeP7xxxs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -666, + "top": -938, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKunfeP7zeiI=", + "_parent": { + "$ref": "AAAAAAFfKunfeP7xxxs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 685, + "top": 1012, + "width": 129, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageWebPCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKunfeP70wYg=", + "_parent": { + "$ref": "AAAAAAFfKunfeP7xxxs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 685, + "top": 1027, + "width": 129, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFfKunfeP71LpU=", + "_parent": { + "$ref": "AAAAAAFfKunfeP7xxxs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -666, + "top": -938, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 680, + "top": 1005, + "width": 139, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFfKunfeP7yLV4=" + }, + "nameLabel": { + "$ref": "AAAAAAFfKunfeP7zeiI=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFfKunfeP70wYg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFfKunfeP71LpU=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFfKunfeP72L2s=", + "_parent": { + "$ref": "AAAAAAFfKunfeP7w4nM=" + }, + "model": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 680, + "top": 1045, + "width": 144.14501953125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFfKunfeP73sYg=", + "_parent": { + "$ref": "AAAAAAFfKunfeP7w4nM=" + }, + "model": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 680, + "top": 1055, + "width": 144.14501953125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFfKunfeP74CcA=", + "_parent": { + "$ref": "AAAAAAFfKunfeP7w4nM=" + }, + "model": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -317, + "top": -493, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFfKunfeP75I0A=", + "_parent": { + "$ref": "AAAAAAFfKunfeP7w4nM=" + }, + "model": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -317, + "top": -493, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 680, + "top": 1005, + "width": 139, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFfKunfeP7xxxs=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFfKunfeP72L2s=" + }, + "operationCompartment": { + "$ref": "AAAAAAFfKunfeP73sYg=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFfKunfeP74CcA=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFfKunfeP75I0A=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAFfKutJugVTfl4=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKutJuwVU9rw=", + "_parent": { + "$ref": "AAAAAAFfKutJugVTfl4=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 736, + "top": 787, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFfKutJugVTfl4=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKutJuwVVxHc=", + "_parent": { + "$ref": "AAAAAAFfKutJugVTfl4=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 736, + "top": 772, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFfKutJugVTfl4=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKutJuwVWtuI=", + "_parent": { + "$ref": "AAAAAAFfKutJugVTfl4=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 736, + "top": 817, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFfKutJugVTfl4=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFfKtnKU+Dd+kU=" + }, + "tail": { + "$ref": "AAAAAAFfKucZUPTSZzA=" + }, + "lineStyle": 0, + "points": "689:856;689:808;784:808;784:772", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFfKutJuwVU9rw=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFfKutJuwVVxHc=" + }, + "propertyLabel": { + "$ref": "AAAAAAFfKutJuwVWtuI=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFfKuwBKQhKobU=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKuwBKghLk+8=", + "_parent": { + "$ref": "AAAAAAFfKuwBKQhKobU=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 452, + "top": 459, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFfKuwBKQhKobU=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKuwBKghMg6U=", + "_parent": { + "$ref": "AAAAAAFfKuwBKQhKobU=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 452, + "top": 444, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFfKuwBKQhKobU=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKuwBKghNzcQ=", + "_parent": { + "$ref": "AAAAAAFfKuwBKQhKobU=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 452, + "top": 489, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFfKuwBKQhKobU=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFfKulRr/y/5nQ=" + }, + "tail": { + "$ref": "AAAAAAFUmNdXmNnpp1I=" + }, + "lineStyle": 0, + "points": "359:439;359:480;545:480;545:728", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFfKuwBKghLk+8=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFfKuwBKghMg6U=" + }, + "propertyLabel": { + "$ref": "AAAAAAFfKuwBKghNzcQ=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFfKuxM+QnrKEs=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKuxM+AnptLY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKuxM+QnsE1g=", + "_parent": { + "$ref": "AAAAAAFfKuxM+QnrKEs=" + }, + "model": { + "$ref": "AAAAAAFfKuxM+AnptLY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 551, + "top": 576, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFfKuxM+QnrKEs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKuxM+Qntx5Q=", + "_parent": { + "$ref": "AAAAAAFfKuxM+QnrKEs=" + }, + "model": { + "$ref": "AAAAAAFfKuxM+AnptLY=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 566, + "top": 576, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFfKuxM+QnrKEs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKuxM+QnusHg=", + "_parent": { + "$ref": "AAAAAAFfKuxM+QnrKEs=" + }, + "model": { + "$ref": "AAAAAAFfKuxM+AnptLY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 521, + "top": 577, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFfKuxM+QnrKEs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFfKulRr/y/5nQ=" + }, + "tail": { + "$ref": "AAAAAAFUmNdyjto3Jy4=" + }, + "lineStyle": 0, + "points": "536:439;536:728", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFfKuxM+QnsE1g=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFfKuxM+Qntx5Q=" + }, + "propertyLabel": { + "$ref": "AAAAAAFfKuxM+QnusHg=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFfKu3J8hGYD10=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKu3J8hGXH0g=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKu3J8hGZpfY=", + "_parent": { + "$ref": "AAAAAAFfKu3J8hGYD10=" + }, + "model": { + "$ref": "AAAAAAFfKu3J8hGXH0g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 665, + "top": 723, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFfKu3J8hGYD10=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKu3J8xGaIH4=", + "_parent": { + "$ref": "AAAAAAFfKu3J8hGYD10=" + }, + "model": { + "$ref": "AAAAAAFfKu3J8hGXH0g=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 665, + "top": 708, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFfKu3J8hGYD10=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKu3J8xGbcAQ=", + "_parent": { + "$ref": "AAAAAAFfKu3J8hGYD10=" + }, + "model": { + "$ref": "AAAAAAFfKu3J8hGXH0g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 665, + "top": 753, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFfKu3J8hGYD10=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFfKtnKU+Dd+kU=" + }, + "tail": { + "$ref": "AAAAAAFfKulRr/y/5nQ=" + }, + "lineStyle": 0, + "points": "626:744;704:744", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFfKu3J8hGZpfY=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFfKu3J8xGaIH4=" + }, + "propertyLabel": { + "$ref": "AAAAAAFfKu3J8xGbcAQ=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFfKu8vthgM5EM=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKu8vtRgLlUU=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKu8vthgNPAE=", + "_parent": { + "$ref": "AAAAAAFfKu8vthgM5EM=" + }, + "model": { + "$ref": "AAAAAAFfKu8vtRgLlUU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 839, + "top": 861, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFfKu8vthgM5EM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKu8vthgOQwY=", + "_parent": { + "$ref": "AAAAAAFfKu8vthgM5EM=" + }, + "model": { + "$ref": "AAAAAAFfKu8vtRgLlUU=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 839, + "top": 846, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFfKu8vthgM5EM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKu8vtxgPIAE=", + "_parent": { + "$ref": "AAAAAAFfKu8vthgM5EM=" + }, + "model": { + "$ref": "AAAAAAFfKu8vtRgLlUU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 839, + "top": 891, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFfKu8vthgM5EM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFky0klQadyygU=" + }, + "tail": { + "$ref": "AAAAAAFfKumzBf41WYU=" + }, + "lineStyle": 0, + "points": "839:1005;839:882;840:882", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFfKu8vthgNPAE=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFfKu8vthgOQwY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFfKu8vtxgPIAE=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFfKu+znBqrl+4=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKu+znBqqvWQ=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKu+znRqsx/w=", + "_parent": { + "$ref": "AAAAAAFfKu+znBqrl+4=" + }, + "model": { + "$ref": "AAAAAAFfKu+znBqqvWQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 601, + "top": 949, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFfKu+znBqrl+4=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKu+znRqt1Ng=", + "_parent": { + "$ref": "AAAAAAFfKu+znBqrl+4=" + }, + "model": { + "$ref": "AAAAAAFfKu+znBqqvWQ=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 586, + "top": 949, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFfKu+znBqrl+4=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKu+znRquxZo=", + "_parent": { + "$ref": "AAAAAAFfKu+znBqrl+4=" + }, + "model": { + "$ref": "AAAAAAFfKu+znBqqvWQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 630, + "top": 950, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFfKu+znBqrl+4=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFfKucZUPTSZzA=" + }, + "tail": { + "$ref": "AAAAAAFfKumI8P16C6U=" + }, + "lineStyle": 0, + "points": "616:1005;616:908", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFfKu+znRqsx/w=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFfKu+znRqt1Ng=" + }, + "propertyLabel": { + "$ref": "AAAAAAFfKu+znRquxZo=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFfKu/8NRxM/WA=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKu/8NRxNuNE=", + "_parent": { + "$ref": "AAAAAAFfKu/8NRxM/WA=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 697, + "top": 949, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFfKu/8NRxM/WA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKu/8NRxORNY=", + "_parent": { + "$ref": "AAAAAAFfKu/8NRxM/WA=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 682, + "top": 949, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFfKu/8NRxM/WA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFfKu/8NhxPop4=", + "_parent": { + "$ref": "AAAAAAFfKu/8NRxM/WA=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 726, + "top": 950, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFfKu/8NRxM/WA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFfKucZUPTSZzA=" + }, + "tail": { + "$ref": "AAAAAAFfKunfeP7w4nM=" + }, + "lineStyle": 0, + "points": "712:1005;712:908", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFfKu/8NRxNuNE=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFfKu/8NRxORNY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFfKu/8NhxPop4=" + } + }, + { + "_type": "UMLEnumerationView", + "_id": "AAAAAAFkyzWMXW3WYX8=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFkyzWMXW3Xuo4=", + "_parent": { + "$ref": "AAAAAAFkyzWMXW3WYX8=" + }, + "model": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFkyzWMXW3YIfk=", + "_parent": { + "$ref": "AAAAAAFkyzWMXW3Xuo4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1037, + "top": 725, + "width": 142, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«enumeration»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFkyzWMXm3ZU2I=", + "_parent": { + "$ref": "AAAAAAFkyzWMXW3Xuo4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1037, + "top": 740, + "width": 142, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCoderOptions", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFkyzWMXm3aSGo=", + "_parent": { + "$ref": "AAAAAAFkyzWMXW3Xuo4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1037, + "top": 755, + "width": 142, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFkyzWMXm3bNg4=", + "_parent": { + "$ref": "AAAAAAFkyzWMXW3Xuo4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -868, + "top": -592, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1032, + "top": 720, + "width": 152, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFkyzWMXW3YIfk=" + }, + "nameLabel": { + "$ref": "AAAAAAFkyzWMXm3ZU2I=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFkyzWMXm3aSGo=" + }, + "propertyLabel": { + "$ref": "AAAAAAFkyzWMXm3bNg4=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFkyzWMXm3clCg=", + "_parent": { + "$ref": "AAAAAAFkyzWMXW3WYX8=" + }, + "model": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -434, + "top": -296, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFkyzWMXm3dpTo=", + "_parent": { + "$ref": "AAAAAAFkyzWMXW3WYX8=" + }, + "model": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -434, + "top": -296, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFkyzWMXm3elOY=", + "_parent": { + "$ref": "AAAAAAFkyzWMXW3WYX8=" + }, + "model": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -434, + "top": -296, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFkyzWMXm3f5Yw=", + "_parent": { + "$ref": "AAAAAAFkyzWMXW3WYX8=" + }, + "model": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1082.62646484375, + "top": 720, + "width": 130.6689453125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLEnumerationLiteralCompartmentView", + "_id": "AAAAAAFkyzWMXm3ggcQ=", + "_parent": { + "$ref": "AAAAAAFkyzWMXW3WYX8=" + }, + "model": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "subViews": [ + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkyzXANXBwzUk=", + "_parent": { + "$ref": "AAAAAAFkyzWMXm3ggcQ=" + }, + "model": { + "$ref": "AAAAAAFkyzXADnBSFdc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 877, + "top": -118, + "width": 172.8212890625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "decodeFirstFrameOnly", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkyzaoYHZ3vVI=", + "_parent": { + "$ref": "AAAAAAFkyzWMXm3ggcQ=" + }, + "model": { + "$ref": "AAAAAAFkyzZGYHJ5+5E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 877, + "top": -103, + "width": 172.8212890625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "decodeScaleFactor", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkyzbTSneLWPA=", + "_parent": { + "$ref": "AAAAAAFkyzWMXm3ggcQ=" + }, + "model": { + "$ref": "AAAAAAFkyzbTKndtAbI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 877, + "top": -88, + "width": 172.8212890625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "encodeFirstFrameOnly", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkyzbyEnjWI/0=", + "_parent": { + "$ref": "AAAAAAFkyzWMXm3ggcQ=" + }, + "model": { + "$ref": "AAAAAAFkyzbx8ni4xXQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 877, + "top": -73, + "width": 172.8212890625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "encodeCompressionQuality", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1032, + "top": 773, + "width": 182.8212890625, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1032, + "top": 720, + "width": 152, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFkyzWMXW3Xuo4=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFkyzWMXm3clCg=" + }, + "operationCompartment": { + "$ref": "AAAAAAFkyzWMXm3dpTo=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFkyzWMXm3elOY=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFkyzWMXm3f5Yw=" + }, + "suppressLiterals": true, + "enumerationLiteralCompartment": { + "$ref": "AAAAAAFkyzWMXm3ggcQ=" + } + }, + { + "_type": "UMLEnumerationView", + "_id": "AAAAAAFkyznULX7p8HI=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFkyznULX7q3Hk=", + "_parent": { + "$ref": "AAAAAAFkyznULX7p8HI=" + }, + "model": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFkyznULX7rscQ=", + "_parent": { + "$ref": "AAAAAAFkyznULX7q3Hk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 173, + "top": 773, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«enumeration»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFkyznULX7sbRU=", + "_parent": { + "$ref": "AAAAAAFkyznULX7q3Hk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 173, + "top": 788, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageFormat", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFkyznULX7tVqI=", + "_parent": { + "$ref": "AAAAAAFkyznULX7q3Hk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 173, + "top": 803, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFkyznULX7uVEM=", + "_parent": { + "$ref": "AAAAAAFkyznULX7q3Hk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -2638, + "top": -668, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 168, + "top": 768, + "width": 128, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFkyznULX7rscQ=" + }, + "nameLabel": { + "$ref": "AAAAAAFkyznULX7sbRU=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFkyznULX7tVqI=" + }, + "propertyLabel": { + "$ref": "AAAAAAFkyznULX7uVEM=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFkyznULX7vLLA=", + "_parent": { + "$ref": "AAAAAAFkyznULX7p8HI=" + }, + "model": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1319, + "top": -334, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFkyznULX7wyLQ=", + "_parent": { + "$ref": "AAAAAAFkyznULX7p8HI=" + }, + "model": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1319, + "top": -334, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFkyznULX7xEMI=", + "_parent": { + "$ref": "AAAAAAFkyznULX7p8HI=" + }, + "model": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1319, + "top": -334, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFkyznULn7yH8I=", + "_parent": { + "$ref": "AAAAAAFkyznULX7p8HI=" + }, + "model": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1319, + "top": -334, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLEnumerationLiteralCompartmentView", + "_id": "AAAAAAFkyznULn7z8io=", + "_parent": { + "$ref": "AAAAAAFkyznULX7p8HI=" + }, + "model": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "subViews": [ + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkyznUZX8uFOA=", + "_parent": { + "$ref": "AAAAAAFkyznULn7z8io=" + }, + "model": { + "$ref": "AAAAAAFkyzm7rX6TNK0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -67, + "top": -142, + "width": 123.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "underfined", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkyznizX/x8eE=", + "_parent": { + "$ref": "AAAAAAFkyznULn7z8io=" + }, + "model": { + "$ref": "AAAAAAFkyzniln/T7fg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -67, + "top": -127, + "width": 123.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "JPEG", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkyzoEB4E8A3k=", + "_parent": { + "$ref": "AAAAAAFkyznULn7z8io=" + }, + "model": { + "$ref": "AAAAAAFkyzoDz4EeE/4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -67, + "top": -112, + "width": 123.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "PNG", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkyzoi5oKHuTU=", + "_parent": { + "$ref": "AAAAAAFkyznULn7z8io=" + }, + "model": { + "$ref": "AAAAAAFkyzoisIJpxLA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -67, + "top": -97, + "width": 123.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "GIF", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkyzo1ToPSKEU=", + "_parent": { + "$ref": "AAAAAAFkyznULn7z8io=" + }, + "model": { + "$ref": "AAAAAAFkyzo1F4O0qHE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -67, + "top": -82, + "width": 123.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "TIFF", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkyzpUU4UdoNA=", + "_parent": { + "$ref": "AAAAAAFkyznULn7z8io=" + }, + "model": { + "$ref": "AAAAAAFkyzpUIIT/rq0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -67, + "top": -67, + "width": 123.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "WebP", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkyzqLV4bVho4=", + "_parent": { + "$ref": "AAAAAAFkyznULn7z8io=" + }, + "model": { + "$ref": "AAAAAAFkyzqLIIa3Chg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -67, + "top": -52, + "width": 123.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "HEIC", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 168, + "top": 821, + "width": 133.82373046875, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 168, + "top": 768, + "width": 128, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFkyznULX7q3Hk=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFkyznULX7vLLA=" + }, + "operationCompartment": { + "$ref": "AAAAAAFkyznULX7wyLQ=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFkyznULX7xEMI=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFkyznULn7yH8I=" + }, + "suppressLiterals": true, + "enumerationLiteralCompartment": { + "$ref": "AAAAAAFkyznULn7z8io=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFky0TjgJYYOQE=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFky0TjgJYZ1Mk=", + "_parent": { + "$ref": "AAAAAAFky0TjgJYYOQE=" + }, + "model": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFky0TjgJYac8s=", + "_parent": { + "$ref": "AAAAAAFky0TjgJYZ1Mk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1109, + "top": 861, + "width": 178, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky0TjgJYbQ8M=", + "_parent": { + "$ref": "AAAAAAFky0TjgJYZ1Mk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1109, + "top": 876, + "width": 178, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDAnimatedImageProvider", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky0TjgJYc4HY=", + "_parent": { + "$ref": "AAAAAAFky0TjgJYZ1Mk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1109, + "top": 891, + "width": 178, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky0TjgJYdXc8=", + "_parent": { + "$ref": "AAAAAAFky0TjgJYZ1Mk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 374, + "top": -1120, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1104, + "top": 856, + "width": 188, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFky0TjgJYac8s=" + }, + "nameLabel": { + "$ref": "AAAAAAFky0TjgJYbQ8M=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFky0TjgJYc4HY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky0TjgJYdXc8=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFky0TjgJYex1M=", + "_parent": { + "$ref": "AAAAAAFky0TjgJYYOQE=" + }, + "model": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1104, + "top": 909, + "width": 297, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFky0TjgZYffJE=", + "_parent": { + "$ref": "AAAAAAFky0TjgJYYOQE=" + }, + "model": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky0WahZkgnmc=", + "_parent": { + "$ref": "AAAAAAFky0TjgZYffJE=" + }, + "model": { + "$ref": "AAAAAAFky0WaTJkCiCI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1085, + "top": -38, + "width": 244.9052734375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animatedImageData(): Data", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky0bXcJx1ENs=", + "_parent": { + "$ref": "AAAAAAFky0TjgZYffJE=" + }, + "model": { + "$ref": "AAAAAAFky0bXOZxXYmQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1085, + "top": -23, + "width": 244.9052734375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animatedImageFrameCount(): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky0d4PZ6Copo=", + "_parent": { + "$ref": "AAAAAAFky0TjgZYffJE=" + }, + "model": { + "$ref": "AAAAAAFky0d4BJ5ka1A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1085, + "top": -8, + "width": 244.9052734375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animatedImageLoopCount(): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky0fVzqCP8vQ=", + "_parent": { + "$ref": "AAAAAAFky0TjgZYffJE=" + }, + "model": { + "$ref": "AAAAAAFky0fVlaBxwo0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1085, + "top": 7, + "width": 244.9052734375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animatedImageFrame(index): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky0hYOKN4s7Q=", + "_parent": { + "$ref": "AAAAAAFky0TjgZYffJE=" + }, + "model": { + "$ref": "AAAAAAFky0hX/6NafH4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1085, + "top": 22, + "width": 244.9052734375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animatedImageDuration(index): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1104, + "top": 909, + "width": 254.9052734375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFky0TjgZYgifQ=", + "_parent": { + "$ref": "AAAAAAFky0TjgJYYOQE=" + }, + "model": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 187, + "top": -560, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFky0TjgZYhrcA=", + "_parent": { + "$ref": "AAAAAAFky0TjgJYYOQE=" + }, + "model": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 187, + "top": -560, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1104, + "top": 856, + "width": 212, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFky0TjgJYZ1Mk=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFky0TjgJYex1M=" + }, + "operationCompartment": { + "$ref": "AAAAAAFky0TjgZYffJE=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFky0TjgZYgifQ=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFky0TjgZYhrcA=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFky0klQadyygU=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFky0klQadzX7Q=", + "_parent": { + "$ref": "AAAAAAFky0klQadyygU=" + }, + "model": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFky0klQad0y/U=", + "_parent": { + "$ref": "AAAAAAFky0klQadzX7Q=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 845, + "top": 861, + "width": 162, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky0klQad1HrY=", + "_parent": { + "$ref": "AAAAAAFky0klQadzX7Q=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 845, + "top": 876, + "width": 162, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDAnimatedImageCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky0klQad2bmw=", + "_parent": { + "$ref": "AAAAAAFky0klQadzX7Q=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 845, + "top": 891, + "width": 162, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky0klQad3A0I=", + "_parent": { + "$ref": "AAAAAAFky0klQadzX7Q=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -550, + "top": -1282, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 840, + "top": 856, + "width": 172, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFky0klQad0y/U=" + }, + "nameLabel": { + "$ref": "AAAAAAFky0klQad1HrY=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFky0klQad2bmw=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky0klQad3A0I=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFky0klQad4uD0=", + "_parent": { + "$ref": "AAAAAAFky0klQadyygU=" + }, + "model": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -275, + "top": -641, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFky0klQad5Nuo=", + "_parent": { + "$ref": "AAAAAAFky0klQadyygU=" + }, + "model": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky0rW4rVwnl4=", + "_parent": { + "$ref": "AAAAAAFky0klQad5Nuo=" + }, + "model": { + "$ref": "AAAAAAFky0rWqbVSTp8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 797, + "top": -62, + "width": 196.27783203125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(data, options)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 840, + "top": 909, + "width": 206.27783203125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFky0klQqd6MuE=", + "_parent": { + "$ref": "AAAAAAFky0klQadyygU=" + }, + "model": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -275, + "top": -641, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFky0klQqd7LaY=", + "_parent": { + "$ref": "AAAAAAFky0klQadyygU=" + }, + "model": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -275, + "top": -641, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 840, + "top": 856, + "width": 196, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFky0klQadzX7Q=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFky0klQad4uD0=" + }, + "operationCompartment": { + "$ref": "AAAAAAFky0klQad5Nuo=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFky0klQqd6MuE=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFky0klQqd7LaY=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAFky0me66xK1BU=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky0me66xL/wA=", + "_parent": { + "$ref": "AAAAAAFky0me66xK1BU=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 859, + "top": 817, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky0me66xK1BU=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky0me66xMBqo=", + "_parent": { + "$ref": "AAAAAAFky0me66xK1BU=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 859, + "top": 832, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFky0me66xK1BU=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky0me66xNf5Q=", + "_parent": { + "$ref": "AAAAAAFky0me66xK1BU=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 860, + "top": 787, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky0me66xK1BU=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFfKtnKU+Dd+kU=" + }, + "tail": { + "$ref": "AAAAAAFky0klQadyygU=" + }, + "lineStyle": 0, + "points": "937:856;937:808;784:808;784:772", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFky0me66xL/wA=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFky0me66xMBqo=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky0me66xNf5Q=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAFky0n7HK873v0=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky0n7HK88V4A=", + "_parent": { + "$ref": "AAAAAAFky0n7HK873v0=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1069, + "top": 861, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky0n7HK873v0=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky0n7HK899Mg=", + "_parent": { + "$ref": "AAAAAAFky0n7HK873v0=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1069, + "top": 846, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFky0n7HK873v0=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky0n7HK8+Zb0=", + "_parent": { + "$ref": "AAAAAAFky0n7HK873v0=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1069, + "top": 891, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky0n7HK873v0=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFky0TjgJYYOQE=" + }, + "tail": { + "$ref": "AAAAAAFky0klQadyygU=" + }, + "lineStyle": 0, + "points": "1035:882;1104:882", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFky0n7HK88V4A=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFky0n7HK899Mg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky0n7HK8+Zb0=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFky05PhsCfoa8=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKu8vtRgLlUU=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky05PhsCgpKk=", + "_parent": { + "$ref": "AAAAAAFky05PhsCfoa8=" + }, + "model": { + "$ref": "AAAAAAFfKu8vtRgLlUU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 787, + "top": 977, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky05PhsCfoa8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky05PhsCh4Ao=", + "_parent": { + "$ref": "AAAAAAFky05PhsCfoa8=" + }, + "model": { + "$ref": "AAAAAAFfKu8vtRgLlUU=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 787, + "top": 992, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFky05PhsCfoa8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky05PhsCiq5A=", + "_parent": { + "$ref": "AAAAAAFky05PhsCfoa8=" + }, + "model": { + "$ref": "AAAAAAFfKu8vtRgLlUU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 788, + "top": 947, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky05PhsCfoa8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFfKucZUPTSZzA=" + }, + "tail": { + "$ref": "AAAAAAFfKumzBf41WYU=" + }, + "lineStyle": 0, + "points": "887:1005;887:968;689:968;689:908", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFky05PhsCgpKk=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFky05PhsCh4Ao=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky05PhsCiq5A=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFky07WV8LRjTA=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky07WV8LS3+4=", + "_parent": { + "$ref": "AAAAAAFky07WV8LRjTA=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 843, + "top": 963, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky07WV8LRjTA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky07WV8LTM8c=", + "_parent": { + "$ref": "AAAAAAFky07WV8LRjTA=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 843, + "top": 948, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFky07WV8LRjTA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky07WV8LUgnU=", + "_parent": { + "$ref": "AAAAAAFky07WV8LRjTA=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 843, + "top": 993, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky07WV8LRjTA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFky0klQadyygU=" + }, + "tail": { + "$ref": "AAAAAAFfKunfeP7w4nM=" + }, + "lineStyle": 0, + "points": "749:1005;749:984;937:984;937:908", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFky07WV8LS3+4=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFky07WV8LTM8c=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky07WV8LUgnU=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFky08/ucTKxlE=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFky08/usTLvaM=", + "_parent": { + "$ref": "AAAAAAFky08/ucTKxlE=" + }, + "model": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFky08/usTMwbw=", + "_parent": { + "$ref": "AAAAAAFky08/usTLvaM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1344, + "top": -340, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky08/usTN3ZM=", + "_parent": { + "$ref": "AAAAAAFky08/usTLvaM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 965, + "top": 1012, + "width": 130, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageAPNGCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky08/usTOnng=", + "_parent": { + "$ref": "AAAAAAFky08/usTLvaM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 965, + "top": 1027, + "width": 130, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky08/usTPWAE=", + "_parent": { + "$ref": "AAAAAAFky08/usTLvaM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1344, + "top": -340, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 960, + "top": 1005, + "width": 140, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFky08/usTMwbw=" + }, + "nameLabel": { + "$ref": "AAAAAAFky08/usTN3ZM=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFky08/usTOnng=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky08/usTPWAE=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFky08/usTQBTU=", + "_parent": { + "$ref": "AAAAAAFky08/ucTKxlE=" + }, + "model": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 960, + "top": 1045, + "width": 145.4208984375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFky08/usTR//k=", + "_parent": { + "$ref": "AAAAAAFky08/ucTKxlE=" + }, + "model": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 960, + "top": 1055, + "width": 145.4208984375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFky08/usTSXbk=", + "_parent": { + "$ref": "AAAAAAFky08/ucTKxlE=" + }, + "model": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 688, + "top": -194, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFky08/usTTuM0=", + "_parent": { + "$ref": "AAAAAAFky08/ucTKxlE=" + }, + "model": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 688, + "top": -194, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 960, + "top": 1005, + "width": 140, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFky08/usTLvaM=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFky08/usTQBTU=" + }, + "operationCompartment": { + "$ref": "AAAAAAFky08/usTR//k=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFky08/usTSXbk=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFky08/usTTuM0=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFky09rEcZXveU=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky09rEcZYHYs=", + "_parent": { + "$ref": "AAAAAAFky09rEcZXveU=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 858, + "top": 961, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky09rEcZXveU=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky09rEcZZ84s=", + "_parent": { + "$ref": "AAAAAAFky09rEcZXveU=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 858, + "top": 976, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFky09rEcZXveU=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky09rEcZaAxY=", + "_parent": { + "$ref": "AAAAAAFky09rEcZXveU=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 859, + "top": 931, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky09rEcZXveU=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFfKucZUPTSZzA=" + }, + "tail": { + "$ref": "AAAAAAFky08/ucTKxlE=" + }, + "lineStyle": 0, + "points": "1029:1005;1029:952;689:952;689:908", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFky09rEcZYHYs=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFky09rEcZZ84s=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky09rEcZaAxY=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFky0+ZAshTC4M=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky0+ZAshUzqk=", + "_parent": { + "$ref": "AAAAAAFky0+ZAshTC4M=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1001, + "top": 949, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky0+ZAshTC4M=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky0+ZAshVR6A=", + "_parent": { + "$ref": "AAAAAAFky0+ZAshTC4M=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 986, + "top": 949, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFky0+ZAshTC4M=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky0+ZAshWH+c=", + "_parent": { + "$ref": "AAAAAAFky0+ZAshTC4M=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1030, + "top": 950, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky0+ZAshTC4M=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFky0klQadyygU=" + }, + "tail": { + "$ref": "AAAAAAFky08/ucTKxlE=" + }, + "lineStyle": 0, + "points": "1016:1005;1016:908", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFky0+ZAshUzqk=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFky0+ZAshVR6A=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky0+ZAshWH+c=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFky1BcrcutT/I=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFky1A/vstXuLs=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFky1BcrcuuDJU=", + "_parent": { + "$ref": "AAAAAAFky1BcrcutT/I=" + }, + "model": { + "$ref": "AAAAAAFky1A/vstXuLs=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFky1BcrcuvbgQ=", + "_parent": { + "$ref": "AAAAAAFky1BcrcuuDJU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -358, + "top": -716, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky1BcrcuwPow=", + "_parent": { + "$ref": "AAAAAAFky1BcrcuuDJU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 173, + "top": 727, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageFrame", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky1BcrcuxnNs=", + "_parent": { + "$ref": "AAAAAAFky1BcrcuuDJU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 173, + "top": 742, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky1BcrcuyQ14=", + "_parent": { + "$ref": "AAAAAAFky1BcrcuuDJU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -358, + "top": -716, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 168, + "top": 720, + "width": 128, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFky1BcrcuvbgQ=" + }, + "nameLabel": { + "$ref": "AAAAAAFky1BcrcuwPow=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFky1BcrcuxnNs=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky1BcrcuyQ14=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFky1BcrcuzyGg=", + "_parent": { + "$ref": "AAAAAAFky1BcrcutT/I=" + }, + "model": { + "$ref": "AAAAAAFky1A/vstXuLs=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky1B7icxd0sI=", + "_parent": { + "$ref": "AAAAAAFky1BcrcuzyGg=" + }, + "model": { + "$ref": "AAAAAAFky1B7UMw/+L4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -67, + "top": -139, + "width": 134.5830078125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+image", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky1Cc7M2o1Ts=", + "_parent": { + "$ref": "AAAAAAFky1BcrcuzyGg=" + }, + "model": { + "$ref": "AAAAAAFky1CcsM2KQ34=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -67, + "top": -124, + "width": 134.5830078125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+duration", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 168, + "top": 760, + "width": 144.5830078125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFky1Bcrcu0yh0=", + "_parent": { + "$ref": "AAAAAAFky1BcrcutT/I=" + }, + "model": { + "$ref": "AAAAAAFky1A/vstXuLs=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky1DNcs7znZo=", + "_parent": { + "$ref": "AAAAAAFky1Bcrcu0yh0=" + }, + "model": { + "$ref": "AAAAAAFky1DNOM7VKvU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -67, + "top": -101, + "width": 134.5830078125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(image, duration)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 168, + "top": 798, + "width": 144.5830078125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFky1Bcrcu18eQ=", + "_parent": { + "$ref": "AAAAAAFky1BcrcutT/I=" + }, + "model": { + "$ref": "AAAAAAFky1A/vstXuLs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -179, + "top": -358, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFky1Bcrcu2loE=", + "_parent": { + "$ref": "AAAAAAFky1BcrcutT/I=" + }, + "model": { + "$ref": "AAAAAAFky1A/vstXuLs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -179, + "top": -358, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 168, + "top": 720, + "width": 128, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFky1BcrcuuDJU=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFky1BcrcuzyGg=" + }, + "operationCompartment": { + "$ref": "AAAAAAFky1Bcrcu0yh0=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFky1Bcrcu18eQ=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFky1Bcrcu2loE=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFky1JgrdWdprE=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFky1JgrdWeclc=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWdprE=" + }, + "model": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFky1JgrdWfWvc=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWeclc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -3146, + "top": -92, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky1JgrdWgdis=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWeclc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 727, + "width": 133, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCoderHelper", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky1JgrdWhL9o=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWeclc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 742, + "width": 133, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky1JgrdWiAQ4=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWeclc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -3146, + "top": -92, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 720, + "width": 143, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFky1JgrdWfWvc=" + }, + "nameLabel": { + "$ref": "AAAAAAFky1JgrdWgdis=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFky1JgrdWhL9o=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky1JgrdWiAQ4=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFky1JgrdWjpCE=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWdprE=" + }, + "model": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 760, + "width": 418.12255859375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFky1JgrdWkt1M=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWdprE=" + }, + "model": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky1Jg49Xe3O8=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWkt1M=" + }, + "model": { + "$ref": "AAAAAAFky1HlrdRLhc8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -129, + "width": 408.12255859375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+animatedImage(frames): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky1MmZdpwbmM=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWkt1M=" + }, + "model": { + "$ref": "AAAAAAFky1MmItpS0IE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -114, + "width": 408.12255859375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+frames(animatedImage): Array ", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky1QnC9+RHYI=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWkt1M=" + }, + "model": { + "$ref": "AAAAAAFky1Qmzd9zXiU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -99, + "width": 408.12255859375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+colorSpaceGetDeviceRGB(): CGColorSpace", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky1S1d+ILAHs=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWkt1M=" + }, + "model": { + "$ref": "AAAAAAFky1S1OuHtMmU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -84, + "width": 408.12255859375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+cgImageContainsAlpha(cgImage): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky1WoB+VhirQ=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWkt1M=" + }, + "model": { + "$ref": "AAAAAAFky1WnxOVDz7I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -69, + "width": 408.12255859375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+cgImageCreateDecoded(cgImage): CGImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky1ZyIei3ADc=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWkt1M=" + }, + "model": { + "$ref": "AAAAAAFky1Zx3+iZ+Sc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -54, + "width": 408.12255859375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+cgImageCreateDecoded(cgImage, orientation): CGImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky1co2Ozpop8=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWkt1M=" + }, + "model": { + "$ref": "AAAAAAFky1comezL+vc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -39, + "width": 408.12255859375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+decodedImage(image): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky1ejI/A/KdY=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWkt1M=" + }, + "model": { + "$ref": "AAAAAAFky1ei5PAhNRU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -24, + "width": 408.12255859375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+decodedAndScaledDownImage(image, limitBytes): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky1gyzfRxXEA=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWkt1M=" + }, + "model": { + "$ref": "AAAAAAFky1gyjvRTopk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -9, + "width": 408.12255859375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+imageOrientation(exifOrientation): UIImageOrientation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky1jNIffHA0I=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWkt1M=" + }, + "model": { + "$ref": "AAAAAAFky1jM4Pep+/8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 6, + "width": 408.12255859375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+exifOrientation(imageOrientation): CGImagePropertyOrientation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 770, + "width": 418.12255859375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFky1JgrdWlOLU=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWdprE=" + }, + "model": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1573, + "top": -46, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFky1JgrdWmRCI=", + "_parent": { + "$ref": "AAAAAAFky1JgrdWdprE=" + }, + "model": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1573, + "top": -46, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 720, + "width": 143, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFky1JgrdWeclc=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFky1JgrdWjpCE=" + }, + "operationCompartment": { + "$ref": "AAAAAAFky1JgrdWkt1M=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFky1JgrdWlOLU=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFky1JgrdWmRCI=" + } + }, + { + "_type": "UMLEnumerationView", + "_id": "AAAAAAFky2qLtUbjGdc=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFky2qLtUbkWng=", + "_parent": { + "$ref": "AAAAAAFky2qLtUbjGdc=" + }, + "model": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFky2qLtUbl3mg=", + "_parent": { + "$ref": "AAAAAAFky2qLtUbkWng=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 877, + "top": 501, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«enumeration»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky2qLtUbmMSA=", + "_parent": { + "$ref": "AAAAAAFky2qLtUbkWng=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 877, + "top": 516, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloaderOptions", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky2qLtUbnIEo=", + "_parent": { + "$ref": "AAAAAAFky2qLtUbkWng=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 877, + "top": 531, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky2qLtUboc2g=", + "_parent": { + "$ref": "AAAAAAFky2qLtUbkWng=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -2944, + "top": -382, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 872, + "top": 496, + "width": 216, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFky2qLtUbl3mg=" + }, + "nameLabel": { + "$ref": "AAAAAAFky2qLtUbmMSA=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFky2qLtUbnIEo=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky2qLtUboc2g=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFky2qLtUbpRfw=", + "_parent": { + "$ref": "AAAAAAFky2qLtUbjGdc=" + }, + "model": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1472, + "top": -191, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFky2qLtUbqtbo=", + "_parent": { + "$ref": "AAAAAAFky2qLtUbjGdc=" + }, + "model": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1472, + "top": -191, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFky2qLtUbrsaw=", + "_parent": { + "$ref": "AAAAAAFky2qLtUbjGdc=" + }, + "model": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1472, + "top": -191, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFky2qLtUbsAw8=", + "_parent": { + "$ref": "AAAAAAFky2qLtUbjGdc=" + }, + "model": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1472, + "top": -191, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLEnumerationLiteralCompartmentView", + "_id": "AAAAAAFky2qLtkbtNaQ=", + "_parent": { + "$ref": "AAAAAAFky2qLtUbjGdc=" + }, + "model": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "subViews": [ + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFky2qL8Ecoz3g=", + "_parent": { + "$ref": "AAAAAAFky2qLtkbtNaQ=" + }, + "model": { + "$ref": "AAAAAAFUmODurehEneQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 612, + "top": -302, + "width": 220.1494140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "lowPriority", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFky2qL8Ucr3/Y=", + "_parent": { + "$ref": "AAAAAAFky2qLtkbtNaQ=" + }, + "model": { + "$ref": "AAAAAAFUmOD23ehlAns=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 612, + "top": -287, + "width": 220.1494140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "progressiveLoad", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFky2qL8UcuY84=", + "_parent": { + "$ref": "AAAAAAFky2qLtkbtNaQ=" + }, + "model": { + "$ref": "AAAAAAFUmOD+neiGg3g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 612, + "top": -272, + "width": 220.1494140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "useNSURLCache", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFky2qL8UcxPJY=", + "_parent": { + "$ref": "AAAAAAFky2qLtkbtNaQ=" + }, + "model": { + "$ref": "AAAAAAFUmOEGbeinNtM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 612, + "top": -257, + "width": 220.1494140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "ignoreCachedResponse", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFky2qL8kc0xxw=", + "_parent": { + "$ref": "AAAAAAFky2qLtkbtNaQ=" + }, + "model": { + "$ref": "AAAAAAFUmOENpujIT/I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 612, + "top": -242, + "width": 220.1494140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "continueInBackground", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFky2qL8kc3keI=", + "_parent": { + "$ref": "AAAAAAFky2qLtkbtNaQ=" + }, + "model": { + "$ref": "AAAAAAFUmOEVzujp/Q0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 612, + "top": -227, + "width": 220.1494140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "handleCookies", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFky2qL8kc6axs=", + "_parent": { + "$ref": "AAAAAAFky2qLtkbtNaQ=" + }, + "model": { + "$ref": "AAAAAAFUmOEc/ekKMBo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 612, + "top": -212, + "width": 220.1494140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "allowInvalidSSLCertificates", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFky2qL8kc951k=", + "_parent": { + "$ref": "AAAAAAFky2qLtkbtNaQ=" + }, + "model": { + "$ref": "AAAAAAFUmOEkLekrSQE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 612, + "top": -197, + "width": 220.1494140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "highPriority", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFky2uheFTmU3k=", + "_parent": { + "$ref": "AAAAAAFky2qLtkbtNaQ=" + }, + "model": { + "$ref": "AAAAAAFky2uhM1TIKQ4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 612, + "top": -182, + "width": 220.1494140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "scaleDownLargeImages", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFky2vJqlYxUGo=", + "_parent": { + "$ref": "AAAAAAFky2qLtkbtNaQ=" + }, + "model": { + "$ref": "AAAAAAFky2vJY1YTwQk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 612, + "top": -167, + "width": 220.1494140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "avoidDecodeImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFky2vioFd8Lzo=", + "_parent": { + "$ref": "AAAAAAFky2qLtkbtNaQ=" + }, + "model": { + "$ref": "AAAAAAFky2viY1deXps=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 612, + "top": -152, + "width": 220.1494140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "decodeFirstFrameOnly", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFky2v8GFjHCVE=", + "_parent": { + "$ref": "AAAAAAFky2qLtkbtNaQ=" + }, + "model": { + "$ref": "AAAAAAFky2v7z1ipMKY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 612, + "top": -137, + "width": 220.1494140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "preloadAllFrames", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 872, + "top": 549, + "width": 230.1494140625, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 872, + "top": 496, + "width": 216, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFky2qLtUbkWng=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFky2qLtUbpRfw=" + }, + "operationCompartment": { + "$ref": "AAAAAAFky2qLtUbqtbo=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFky2qLtUbrsaw=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFky2qLtUbsAw8=" + }, + "suppressLiterals": true, + "enumerationLiteralCompartment": { + "$ref": "AAAAAAFky2qLtkbtNaQ=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFky20z4Fyf8pw=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky20z4FygIHU=", + "_parent": { + "$ref": "AAAAAAFky20z4Fyf8pw=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1182, + "top": 276, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky20z4Fyf8pw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky20z4FyhJEU=", + "_parent": { + "$ref": "AAAAAAFky20z4Fyf8pw=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1167, + "top": 276, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFky20z4Fyf8pw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky20z4Fyi3L8=", + "_parent": { + "$ref": "AAAAAAFky20z4Fyf8pw=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1212, + "top": 277, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky20z4Fyf8pw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmNWcUNb3p+o=" + }, + "tail": { + "$ref": "AAAAAAFXmuWYrYcCa9s=" + }, + "lineStyle": 0, + "points": "1040:283;1197:283;1197:180", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFky20z4FygIHU=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFky20z4FyhJEU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky20z4Fyi3L8=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFky2+2+WTD+rs=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFky2+2+mTEkMo=", + "_parent": { + "$ref": "AAAAAAFky2+2+WTD+rs=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFky2+2+mTFqBU=", + "_parent": { + "$ref": "AAAAAAFky2+2+mTEkMo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 485, + "top": 309, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky2+2+mTGvtk=", + "_parent": { + "$ref": "AAAAAAFky2+2+mTEkMo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 485, + "top": 324, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageLoader", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky2+2+mTHELQ=", + "_parent": { + "$ref": "AAAAAAFky2+2+mTEkMo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 485, + "top": 339, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky2+2+mTIPdI=", + "_parent": { + "$ref": "AAAAAAFky2+2+mTEkMo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -878, + "top": -636, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 480, + "top": 304, + "width": 138, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFky2+2+mTFqBU=" + }, + "nameLabel": { + "$ref": "AAAAAAFky2+2+mTGvtk=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFky2+2+mTHELQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky2+2+mTIPdI=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFky2+2+mTJbtU=", + "_parent": { + "$ref": "AAAAAAFky2+2+WTD+rs=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -487, + "top": -350, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFky2+2+mTKkG8=", + "_parent": { + "$ref": "AAAAAAFky2+2+WTD+rs=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky3AzjWhsBd4=", + "_parent": { + "$ref": "AAAAAAFky2+2+mTKkG8=" + }, + "model": { + "$ref": "AAAAAAFky3AzTGhO/lc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 10, + "width": 559.43798828125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+canLoad(url): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky3CxnWtVeUQ=", + "_parent": { + "$ref": "AAAAAAFky2+2+mTKkG8=" + }, + "model": { + "$ref": "AAAAAAFky3CxVms3ePA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 25, + "width": 559.43798828125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+loadImage(url, options, context, progressBlock, completedBlock): SDWebImageOperation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 480, + "top": 357, + "width": 569.43798828125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFky2+2+mTL5XI=", + "_parent": { + "$ref": "AAAAAAFky2+2+WTD+rs=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -487, + "top": -350, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFky2+2+mTM908=", + "_parent": { + "$ref": "AAAAAAFky2+2+WTD+rs=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -487, + "top": -350, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 480, + "top": 304, + "width": 162, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFky2+2+mTEkMo=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFky2+2+mTJbtU=" + }, + "operationCompartment": { + "$ref": "AAAAAAFky2+2+mTKkG8=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFky2+2+mTL5XI=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFky2+2+mTM908=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFky3NiWHjknic=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky3NiWHjlEFE=", + "_parent": { + "$ref": "AAAAAAFky3NiWHjknic=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 537, + "top": 371, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky3NiWHjknic=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky3NiWHjm2LA=", + "_parent": { + "$ref": "AAAAAAFky3NiWHjknic=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 522, + "top": 371, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFky3NiWHjknic=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky3NiWHjnEM0=", + "_parent": { + "$ref": "AAAAAAFky3NiWHjknic=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 566, + "top": 372, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky3NiWHjknic=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFky2+2+WTD+rs=" + }, + "tail": { + "$ref": "AAAAAAFUmNdyjto3Jy4=" + }, + "lineStyle": 0, + "points": "552:400;552:356", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFky3NiWHjlEFE=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFky3NiWHjm2LA=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky3NiWHjnEM0=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFky4wmusk5SLk=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFky4wmusk6LkY=", + "_parent": { + "$ref": "AAAAAAFky4wmusk5SLk=" + }, + "model": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFky4wmusk7izU=", + "_parent": { + "$ref": "AAAAAAFky4wmusk6LkY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -2172, + "top": -404, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky4wmusk8cGE=", + "_parent": { + "$ref": "AAAAAAFky4wmusk6LkY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 885, + "top": 455, + "width": 198, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloaderConfig", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky4wmusk928E=", + "_parent": { + "$ref": "AAAAAAFky4wmusk6LkY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 885, + "top": 470, + "width": 198, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky4wmusk+ipg=", + "_parent": { + "$ref": "AAAAAAFky4wmusk6LkY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -2172, + "top": -404, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 880, + "top": 448, + "width": 208, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFky4wmusk7izU=" + }, + "nameLabel": { + "$ref": "AAAAAAFky4wmusk8cGE=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFky4wmusk928E=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky4wmusk+ipg=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFky4wmu8k/J1g=", + "_parent": { + "$ref": "AAAAAAFky4wmusk5SLk=" + }, + "model": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky4zOa894+O8=", + "_parent": { + "$ref": "AAAAAAFky4wmu8k/J1g=" + }, + "model": { + "$ref": "AAAAAAFky4zOJs9aW9c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 621, + "top": -195, + "width": 211.4404296875, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+default", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky4z+AdGdFgQ=", + "_parent": { + "$ref": "AAAAAAFky4wmu8k/J1g=" + }, + "model": { + "$ref": "AAAAAAFky4z9vtF/kCc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 621, + "top": -180, + "width": 211.4404296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+maxConcurrentDownloads", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky40YKdLodXo=", + "_parent": { + "$ref": "AAAAAAFky4wmu8k/J1g=" + }, + "model": { + "$ref": "AAAAAAFky40X5tLK/zc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 621, + "top": -165, + "width": 211.4404296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+downloadTimeout", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky400aNQzIxc=", + "_parent": { + "$ref": "AAAAAAFky4wmu8k/J1g=" + }, + "model": { + "$ref": "AAAAAAFky400JdQVn+Q=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 621, + "top": -150, + "width": 211.4404296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sessionConfiguration", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky41R+NV+WsM=", + "_parent": { + "$ref": "AAAAAAFky4wmu8k/J1g=" + }, + "model": { + "$ref": "AAAAAAFky41Rt9Vg34c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 621, + "top": -135, + "width": 211.4404296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+operationClass", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky419adbJ1Fg=", + "_parent": { + "$ref": "AAAAAAFky4wmu8k/J1g=" + }, + "model": { + "$ref": "AAAAAAFky419KNarbXU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 621, + "top": -120, + "width": 211.4404296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+executionOrder", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky42aENgUqDM=", + "_parent": { + "$ref": "AAAAAAFky4wmu8k/J1g=" + }, + "model": { + "$ref": "AAAAAAFky42Z0df2Ke8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 621, + "top": -105, + "width": 211.4404296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+urlCredential", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky4241dlfxbY=", + "_parent": { + "$ref": "AAAAAAFky4wmu8k/J1g=" + }, + "model": { + "$ref": "AAAAAAFky424lNlB4TI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 621, + "top": -90, + "width": 211.4404296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+username", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFky43NBdqqt3c=", + "_parent": { + "$ref": "AAAAAAFky4wmu8k/J1g=" + }, + "model": { + "$ref": "AAAAAAFky43MudqMI9E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 621, + "top": -75, + "width": 211.4404296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+password", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 880, + "top": 488, + "width": 221.4404296875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFky4wmu8lA1GA=", + "_parent": { + "$ref": "AAAAAAFky4wmusk5SLk=" + }, + "model": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 880, + "top": 631, + "width": 221.4404296875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFky4wmu8lBQrY=", + "_parent": { + "$ref": "AAAAAAFky4wmusk5SLk=" + }, + "model": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1006, + "top": -498, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFky4wmu8lChHc=", + "_parent": { + "$ref": "AAAAAAFky4wmusk5SLk=" + }, + "model": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1006, + "top": -498, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 880, + "top": 448, + "width": 208, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFky4wmusk6LkY=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFky4wmu8k/J1g=" + }, + "operationCompartment": { + "$ref": "AAAAAAFky4wmu8lA1GA=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFky4wmu8lBQrY=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFky4wmu8lChHc=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFky4+E/+WpkuY=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFky4+E/+WqDBk=", + "_parent": { + "$ref": "AAAAAAFky4+E/+WpkuY=" + }, + "model": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFky4+E/+Wr0ww=", + "_parent": { + "$ref": "AAAAAAFky4+E/+WqDBk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 557, + "top": 541, + "width": 268, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky4+E/+WseEM=", + "_parent": { + "$ref": "AAAAAAFky4+E/+WqDBk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 557, + "top": 556, + "width": 268, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloaderRequestModifier", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky4+E/+Wtul4=", + "_parent": { + "$ref": "AAAAAAFky4+E/+WqDBk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 557, + "top": 571, + "width": 268, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky4+E/+WuKII=", + "_parent": { + "$ref": "AAAAAAFky4+E/+WqDBk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -2878, + "top": -298, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 552, + "top": 536, + "width": 278, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFky4+E/+Wr0ww=" + }, + "nameLabel": { + "$ref": "AAAAAAFky4+E/+WseEM=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFky4+E/+Wtul4=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky4+E/+WuKII=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFky4+E/+Wv22g=", + "_parent": { + "$ref": "AAAAAAFky4+E/+WpkuY=" + }, + "model": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1439, + "top": -149, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFky4+E/+WwXK8=", + "_parent": { + "$ref": "AAAAAAFky4+E/+WpkuY=" + }, + "model": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky5N7jPL2OmA=", + "_parent": { + "$ref": "AAAAAAFky4+E/+WwXK8=" + }, + "model": { + "$ref": "AAAAAAFky5N7SPLYdL0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": -30, + "width": 311.20849609375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+modifiedRequest(request): URLRequest", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 552, + "top": 589, + "width": 321.20849609375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFky4+E/+WxCT0=", + "_parent": { + "$ref": "AAAAAAFky4+E/+WpkuY=" + }, + "model": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1439, + "top": -149, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFky4+E/+WydMY=", + "_parent": { + "$ref": "AAAAAAFky4+E/+WpkuY=" + }, + "model": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1439, + "top": -149, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 552, + "top": 536, + "width": 302, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFky4+E/+WqDBk=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFky4+E/+Wv22g=" + }, + "operationCompartment": { + "$ref": "AAAAAAFky4+E/+WwXK8=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFky4+E/+WxCT0=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFky4+E/+WydMY=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFky5X9gfXo5U4=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFky5X9gfXpNOI=", + "_parent": { + "$ref": "AAAAAAFky5X9gfXo5U4=" + }, + "model": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFky5X9gfXqhUY=", + "_parent": { + "$ref": "AAAAAAFky5X9gfXpNOI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -2884, + "top": 84, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky5X9gfXrQY0=", + "_parent": { + "$ref": "AAAAAAFky5X9gfXpNOI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 573, + "top": 639, + "width": 258, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloaderRequestModifier", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky5X9gfXsmU0=", + "_parent": { + "$ref": "AAAAAAFky5X9gfXpNOI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 573, + "top": 654, + "width": 258, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFky5X9gfXt6rE=", + "_parent": { + "$ref": "AAAAAAFky5X9gfXpNOI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -2884, + "top": 84, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 568, + "top": 632, + "width": 268, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFky5X9gfXqhUY=" + }, + "nameLabel": { + "$ref": "AAAAAAFky5X9gfXrQY0=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFky5X9gfXsmU0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky5X9gfXt6rE=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFky5X9gfXutK4=", + "_parent": { + "$ref": "AAAAAAFky5X9gfXo5U4=" + }, + "model": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 568, + "top": 672, + "width": 287.20849609375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFky5X9gfXvdi4=", + "_parent": { + "$ref": "AAAAAAFky5X9gfXo5U4=" + }, + "model": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFky5ZuhPujNWs=", + "_parent": { + "$ref": "AAAAAAFky5X9gfXvdi4=" + }, + "model": { + "$ref": "AAAAAAFky5ZuM/uFU/4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 325, + "top": 23, + "width": 277.20849609375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(block)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 568, + "top": 682, + "width": 287.20849609375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFky5X9gvXw2hc=", + "_parent": { + "$ref": "AAAAAAFky5X9gfXo5U4=" + }, + "model": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1442, + "top": 42, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFky5X9gvXx2O8=", + "_parent": { + "$ref": "AAAAAAFky5X9gfXo5U4=" + }, + "model": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1442, + "top": 42, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 568, + "top": 632, + "width": 268, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFky5X9gfXpNOI=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFky5X9gfXutK4=" + }, + "operationCompartment": { + "$ref": "AAAAAAFky5X9gfXvdi4=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFky5X9gvXw2hc=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFky5X9gvXx2O8=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFky5YrW/l2DJM=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky5YrW/l3SzI=", + "_parent": { + "$ref": "AAAAAAFky5YrW/l2DJM=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 701, + "top": 592, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky5YrW/l2DJM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky5YrW/l4cDQ=", + "_parent": { + "$ref": "AAAAAAFky5YrW/l2DJM=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 701, + "top": 577, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFky5YrW/l2DJM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFky5YrW/l5k8Y=", + "_parent": { + "$ref": "AAAAAAFky5YrW/l2DJM=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 701, + "top": 622, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFky5YrW/l2DJM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFky4+E/+WpkuY=" + }, + "tail": { + "$ref": "AAAAAAFky5X9gfXo5U4=" + }, + "lineStyle": 0, + "points": "701:632;701:613;702:613;702:588", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFky5YrW/l3SzI=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFky5YrW/l4cDQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFky5YrW/l5k8Y=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFkzOeFlQjK4RM=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFkzOeFlgjLMy8=", + "_parent": { + "$ref": "AAAAAAFkzOeFlQjK4RM=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFkzOeFlgjMfcs=", + "_parent": { + "$ref": "AAAAAAFkzOeFlgjLMy8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 309, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFkzOeFlgjNQCQ=", + "_parent": { + "$ref": "AAAAAAFkzOeFlgjLMy8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 324, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFkzOeFlgjOnZQ=", + "_parent": { + "$ref": "AAAAAAFkzOeFlgjLMy8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 339, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFkzOeFlgjPkCA=", + "_parent": { + "$ref": "AAAAAAFkzOeFlgjLMy8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -82, + "top": -672, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 288, + "top": 304, + "width": 138, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFkzOeFlgjMfcs=" + }, + "nameLabel": { + "$ref": "AAAAAAFkzOeFlgjNQCQ=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFkzOeFlgjOnZQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFkzOeFlgjPkCA=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFkzOeFlgjQ0GA=", + "_parent": { + "$ref": "AAAAAAFkzOeFlQjK4RM=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -33, + "top": -368, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFkzOeFlgjRJRk=", + "_parent": { + "$ref": "AAAAAAFkzOeFlQjK4RM=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFkzOhfQAsuxxY=", + "_parent": { + "$ref": "AAAAAAFkzOeFlgjRJRk=" + }, + "model": { + "$ref": "AAAAAAFkzOhe6QsQ8iE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 373, + "top": 10, + "width": 481.42529296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+queryImage(key, options, context, completionBlock): SDWebImageOperation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFkzOmFkxJ5bYE=", + "_parent": { + "$ref": "AAAAAAFkzOeFlgjRJRk=" + }, + "model": { + "$ref": "AAAAAAFkzOmFQhJb/sw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 373, + "top": 25, + "width": 481.42529296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+store(image, imageData, key, cacheType, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFkzOpilBe/HOM=", + "_parent": { + "$ref": "AAAAAAFkzOeFlgjRJRk=" + }, + "model": { + "$ref": "AAAAAAFkzOpiQxehydI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 373, + "top": 40, + "width": 481.42529296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeImage(key, cacheType, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFkzOrxxhtNGpo=", + "_parent": { + "$ref": "AAAAAAFkzOeFlgjRJRk=" + }, + "model": { + "$ref": "AAAAAAFkzOrxchsvmU0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 373, + "top": 55, + "width": 481.42529296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+containsImage(key, cacheType, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFkzOvatx+3q3M=", + "_parent": { + "$ref": "AAAAAAFkzOeFlgjRJRk=" + }, + "model": { + "$ref": "AAAAAAFkzOvaYx+Z2C8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 373, + "top": 70, + "width": 481.42529296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+clear(cacheType, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 288, + "top": 357, + "width": 491.42529296875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFkzOeFlgjS2Cs=", + "_parent": { + "$ref": "AAAAAAFkzOeFlQjK4RM=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -33, + "top": -368, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFkzOeFlwjTR54=", + "_parent": { + "$ref": "AAAAAAFkzOeFlQjK4RM=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -33, + "top": -368, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 288, + "top": 304, + "width": 162, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFkzOeFlgjLMy8=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFkzOeFlgjQ0GA=" + }, + "operationCompartment": { + "$ref": "AAAAAAFkzOeFlgjRJRk=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFkzOeFlgjS2Cs=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFkzOeFlwjTR54=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFkzOyHOib7nuw=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFkzOyHOib8k38=", + "_parent": { + "$ref": "AAAAAAFkzOyHOib7nuw=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 345, + "top": 371, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFkzOyHOib7nuw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFkzOyHOib9Tn4=", + "_parent": { + "$ref": "AAAAAAFkzOyHOib7nuw=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 330, + "top": 371, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFkzOyHOib7nuw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFkzOyHOib+VWA=", + "_parent": { + "$ref": "AAAAAAFkzOyHOib7nuw=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 374, + "top": 372, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFkzOyHOib7nuw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFkzOeFlQjK4RM=" + }, + "tail": { + "$ref": "AAAAAAFUmNdXmNnpp1I=" + }, + "lineStyle": 0, + "points": "360:400;360:356", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFkzOyHOib8k38=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFkzOyHOib9Tn4=" + }, + "propertyLabel": { + "$ref": "AAAAAAFkzOyHOib+VWA=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFkzOzkvy6ewkc=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFkzOzkvy6fO70=", + "_parent": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 713, + "top": 436, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFkzOzkvy6gSFU=", + "_parent": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 698, + "top": 436, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFkzOzkvy6hFr8=", + "_parent": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 742, + "top": 437, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFkzOzkvy6ifTg=", + "_parent": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 854, + "top": 475, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFkzOzkvy6jfVY=", + "_parent": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 851, + "top": 489, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFkzOzkvy6kEdk=", + "_parent": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 858, + "top": 448, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFkzOzkwC6lxW8=", + "_parent": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 648, + "top": 427, + "width": 46.490234375, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "edgePosition": 0, + "underline": false, + "text": "+config", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFkzOzkwC6meEU=", + "_parent": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 674, + "top": 441, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFkzOzkwC6nP90=", + "_parent": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 667, + "top": 400, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFkzOzkwC6oIqk=", + "_parent": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 371, + "top": 616, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFkzOzkwC6pg2c=", + "_parent": { + "$ref": "AAAAAAFkzOzkvy6ewkc=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 371, + "top": 616, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmNdyjto3Jy4=" + }, + "tail": { + "$ref": "AAAAAAFky4wmusk5SLk=" + }, + "lineStyle": 0, + "points": "880:467;728:467;728:419;646:419", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFkzOzkvy6fO70=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFkzOzkvy6gSFU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFkzOzkvy6hFr8=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFkzOzkvy6ifTg=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFkzOzkvy6jfVY=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFkzOzkvy6kEdk=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFkzOzkwC6lxW8=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFkzOzkwC6meEU=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFkzOzkwC6nP90=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFkzOzkwC6oIqk=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFkzOzkwC6pg2c=" + } + }, + { + "_type": "UMLEnumerationView", + "_id": "AAAAAAFkzO7AJ0YXKM0=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFkzO7AJ0YYoN4=", + "_parent": { + "$ref": "AAAAAAFkzO7AJ0YXKM0=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFkzO7AJ0YZP20=", + "_parent": { + "$ref": "AAAAAAFkzO7AJ0YYoN4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 149, + "width": 132, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«enumeration»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFkzO7AJ0YacO4=", + "_parent": { + "$ref": "AAAAAAFkzO7AJ0YYoN4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 164, + "width": 132, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageOptions", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFkzO7AJ0YbDG0=", + "_parent": { + "$ref": "AAAAAAFkzO7AJ0YYoN4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 179, + "width": 132, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFkzO7AJ0YcY40=", + "_parent": { + "$ref": "AAAAAAFkzO7AJ0YYoN4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -528, + "top": -2176, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 144, + "width": 142, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFkzO7AJ0YZP20=" + }, + "nameLabel": { + "$ref": "AAAAAAFkzO7AJ0YacO4=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFkzO7AJ0YbDG0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFkzO7AJ0YcY40=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFkzO7AJ0YdKRc=", + "_parent": { + "$ref": "AAAAAAFkzO7AJ0YXKM0=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -264, + "top": -1088, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFkzO7AJ0YeuNs=", + "_parent": { + "$ref": "AAAAAAFkzO7AJ0YXKM0=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -264, + "top": -1088, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFkzO7AJ0YfdN4=", + "_parent": { + "$ref": "AAAAAAFkzO7AJ0YXKM0=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -264, + "top": -1088, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFkzO7AKEYgKaM=", + "_parent": { + "$ref": "AAAAAAFkzO7AJ0YXKM0=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -264, + "top": -1088, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLEnumerationLiteralCompartmentView", + "_id": "AAAAAAFkzO7AKEYhG1Y=", + "_parent": { + "$ref": "AAAAAAFkzO7AJ0YXKM0=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "subViews": [ + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkzO7AfUZfsHg=", + "_parent": { + "$ref": "AAAAAAFkzO7AKEYhG1Y=" + }, + "model": { + "$ref": "AAAAAAFUkhys4o27Ge0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 146, + "width": 166.333984375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "retryFailed", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkzO7AfUZidzY=", + "_parent": { + "$ref": "AAAAAAFkzO7AKEYhG1Y=" + }, + "model": { + "$ref": "AAAAAAFUkhza8o2/z9E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 161, + "width": 166.333984375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "lowPriority", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkzO7AfkZoifc=", + "_parent": { + "$ref": "AAAAAAFkzO7AKEYhG1Y=" + }, + "model": { + "$ref": "AAAAAAFUkhzs8o3Fkdk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 176, + "width": 166.333984375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "progressiveLoad", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkzO7AfkZrII0=", + "_parent": { + "$ref": "AAAAAAFkzO7AKEYhG1Y=" + }, + "model": { + "$ref": "AAAAAAFUkhz04o3ItAc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 191, + "width": 166.333984375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "refreshCached", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkzO7Af0ZuRFE=", + "_parent": { + "$ref": "AAAAAAFkzO7AKEYhG1Y=" + }, + "model": { + "$ref": "AAAAAAFUkhz84Y3L96A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 206, + "width": 166.333984375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "continueInBackground", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkzO7AgEZxjX4=", + "_parent": { + "$ref": "AAAAAAFkzO7AKEYhG1Y=" + }, + "model": { + "$ref": "AAAAAAFUkh0C6Y3O214=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 221, + "width": 166.333984375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "handleCookies", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkzO7AgEZ0Cis=", + "_parent": { + "$ref": "AAAAAAFkzO7AKEYhG1Y=" + }, + "model": { + "$ref": "AAAAAAFUkh2TUY3YpnQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 236, + "width": 166.333984375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "allowInvalidSSLCertificates", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkzO7AgUZ3eQo=", + "_parent": { + "$ref": "AAAAAAFkzO7AKEYhG1Y=" + }, + "model": { + "$ref": "AAAAAAFUkh2bqY3bxlE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 251, + "width": 166.333984375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "highPriority", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkzO7AgUZ6fWA=", + "_parent": { + "$ref": "AAAAAAFkzO7AKEYhG1Y=" + }, + "model": { + "$ref": "AAAAAAFUkh2p4Y3e22E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 266, + "width": 166.333984375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "delayPlaceholder", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkzO7AgUZ9Bnw=", + "_parent": { + "$ref": "AAAAAAFkzO7AKEYhG1Y=" + }, + "model": { + "$ref": "AAAAAAFUkh2x+Y3hQmw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 281, + "width": 166.333984375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "transformAnimatedImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkzO7AgUaAY/8=", + "_parent": { + "$ref": "AAAAAAFkzO7AKEYhG1Y=" + }, + "model": { + "$ref": "AAAAAAFUkh31iY3ox50=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 296, + "width": 166.333984375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "avoidAutoSetImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFkzPKukmzcWiw=", + "_parent": { + "$ref": "AAAAAAFkzO7AKEYhG1Y=" + }, + "model": { + "$ref": "AAAAAAFkzPKuPGy7i4M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 311, + "width": 166.333984375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "scaleDownLargeImages", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 197, + "width": 176.333984375, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 144, + "width": 142, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFkzO7AJ0YYoN4=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFkzO7AJ0YdKRc=" + }, + "operationCompartment": { + "$ref": "AAAAAAFkzO7AJ0YeuNs=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFkzO7AJ0YfdN4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFkzO7AKEYgKaM=" + }, + "suppressLiterals": true, + "enumerationLiteralCompartment": { + "$ref": "AAAAAAFkzO7AKEYhG1Y=" + } + }, + { + "_type": "UMLEnumerationView", + "_id": "AAAAAAFk0MTgNZaGzTc=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk0MTgNZaH8+w=", + "_parent": { + "$ref": "AAAAAAFk0MTgNZaGzTc=" + }, + "model": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk0MTgNZaI3gk=", + "_parent": { + "$ref": "AAAAAAFk0MTgNZaH8+w=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 501, + "width": 143, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«enumeration»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0MTgNZaJ57U=", + "_parent": { + "$ref": "AAAAAAFk0MTgNZaH8+w=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 516, + "width": 143, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCacheOptions", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0MTgNZaKXnk=", + "_parent": { + "$ref": "AAAAAAFk0MTgNZaH8+w=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 531, + "width": 143, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0MTgNZaLgs8=", + "_parent": { + "$ref": "AAAAAAFk0MTgNZaH8+w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -176, + "top": -2216, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 496, + "width": 153, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk0MTgNZaI3gk=" + }, + "nameLabel": { + "$ref": "AAAAAAFk0MTgNZaJ57U=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk0MTgNZaKXnk=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0MTgNZaLgs8=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk0MTgNZaM5ZI=", + "_parent": { + "$ref": "AAAAAAFk0MTgNZaGzTc=" + }, + "model": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -80, + "top": -1140, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk0MTgNZaN0Xs=", + "_parent": { + "$ref": "AAAAAAFk0MTgNZaGzTc=" + }, + "model": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -80, + "top": -1140, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk0MTgNpaO78g=", + "_parent": { + "$ref": "AAAAAAFk0MTgNZaGzTc=" + }, + "model": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -80, + "top": -1140, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk0MTgNpaP+yk=", + "_parent": { + "$ref": "AAAAAAFk0MTgNZaGzTc=" + }, + "model": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -80, + "top": -1140, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLEnumerationLiteralCompartmentView", + "_id": "AAAAAAFk0MTgNpaQ1RY=", + "_parent": { + "$ref": "AAAAAAFk0MTgNZaGzTc=" + }, + "model": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "subViews": [ + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk0MTgf5bOQk4=", + "_parent": { + "$ref": "AAAAAAFk0MTgNpaQ1RY=" + }, + "model": { + "$ref": "AAAAAAFk0MQrOpM/jI0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -126, + "width": 151.4677734375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "queryMemoryData", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk0MTgf5bRbrg=", + "_parent": { + "$ref": "AAAAAAFk0MTgNpaQ1RY=" + }, + "model": { + "$ref": "AAAAAAFk0MRCXJO7Xl0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -111, + "width": 151.4677734375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "queryMemoryDataSync", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk0MTggJbUK3g=", + "_parent": { + "$ref": "AAAAAAFk0MTgNpaQ1RY=" + }, + "model": { + "$ref": "AAAAAAFk0MRaJJQ3LUY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -96, + "width": 151.4677734375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "queryDiskDataSync", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk0MTggJbX/g4=", + "_parent": { + "$ref": "AAAAAAFk0MTgNpaQ1RY=" + }, + "model": { + "$ref": "AAAAAAFk0MR51JSzxio=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -81, + "width": 151.4677734375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "scaleDownLargeImages", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk0MTggJbalmg=", + "_parent": { + "$ref": "AAAAAAFk0MTgNpaQ1RY=" + }, + "model": { + "$ref": "AAAAAAFk0MSZXZUvhjA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -66, + "width": 151.4677734375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "avoidDecodeImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk0MTggJbdjZQ=", + "_parent": { + "$ref": "AAAAAAFk0MTgNpaQ1RY=" + }, + "model": { + "$ref": "AAAAAAFk0MS2hZWrSIM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -51, + "width": 151.4677734375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "decodeFirstFrameOnly", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk0MTggZbgngk=", + "_parent": { + "$ref": "AAAAAAFk0MTgNpaQ1RY=" + }, + "model": { + "$ref": "AAAAAAFk0MTONZYnA3o=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -36, + "width": 151.4677734375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "preloadAllFrames", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 549, + "width": 161.4677734375, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 496, + "width": 153, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk0MTgNZaH8+w=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk0MTgNZaM5ZI=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk0MTgNZaN0Xs=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk0MTgNpaO78g=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk0MTgNpaP+yk=" + }, + "suppressLiterals": true, + "enumerationLiteralCompartment": { + "$ref": "AAAAAAFk0MTgNpaQ1RY=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk0MXEuJzHFEg=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0MXEuJzI/kk=", + "_parent": { + "$ref": "AAAAAAFk0MXEuJzHFEg=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 262, + "top": 463, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0MXEuJzHFEg=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0MXEuJzJPew=", + "_parent": { + "$ref": "AAAAAAFk0MXEuJzHFEg=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 277, + "top": 463, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0MXEuJzHFEg=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0MXEuJzKqro=", + "_parent": { + "$ref": "AAAAAAFk0MXEuJzHFEg=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 233, + "top": 464, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0MXEuJzHFEg=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk0MTgNZaGzTc=" + }, + "tail": { + "$ref": "AAAAAAFUmNdXmNnpp1I=" + }, + "lineStyle": 0, + "points": "296:419;248:419;248:522;160:522", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk0MXEuJzI/kk=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk0MXEuJzJPew=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0MXEuJzKqro=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk0NzvdENFORI=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0NzvdENGnUg=", + "_parent": { + "$ref": "AAAAAAFk0NzvdENFORI=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 563, + "top": 501, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0NzvdENFORI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0NzvdENHwvw=", + "_parent": { + "$ref": "AAAAAAFk0NzvdENFORI=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 563, + "top": 486, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0NzvdENFORI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0NzvdUNIzbk=", + "_parent": { + "$ref": "AAAAAAFk0NzvdENFORI=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 563, + "top": 531, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0NzvdENFORI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFky2qLtUbjGdc=" + }, + "tail": { + "$ref": "AAAAAAFUmNdyjto3Jy4=" + }, + "lineStyle": 0, + "points": "563:439;563:522;872:522", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk0NzvdENGnUg=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk0NzvdENHwvw=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0NzvdUNIzbk=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk0N4Oyk+ghOI=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0N4Oyk+hddU=", + "_parent": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 609, + "top": 480, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0N4Oyk+iM/s=", + "_parent": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 594, + "top": 480, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0N4Oyk+jCok=", + "_parent": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 638, + "top": 481, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0N4Oyk+kR3I=", + "_parent": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 609, + "top": 504, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0N4Oyk+liYQ=", + "_parent": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 595, + "top": 501, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0N4Oyk+mQlg=", + "_parent": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 636, + "top": 508, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0N4Oyk+nStE=", + "_parent": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 586, + "top": 458, + "width": 46.490234375, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "edgePosition": 0, + "underline": false, + "text": "+config", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0N4Oyk+oJr0=", + "_parent": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 595, + "top": 461, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0N4Oyk+p2dM=", + "_parent": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 636, + "top": 454, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk0N4Oyk+qa+E=", + "_parent": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 380, + "top": 965, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk0N4Oyk+rD68=", + "_parent": { + "$ref": "AAAAAAFk0N4Oyk+ghOI=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 380, + "top": 965, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmNdyjto3Jy4=" + }, + "tail": { + "$ref": "AAAAAAFky4+E/+WpkuY=" + }, + "lineStyle": 0, + "points": "624:536;624:439", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk0N4Oyk+hddU=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk0N4Oyk+iM/s=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0N4Oyk+jCok=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk0N4Oyk+kR3I=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk0N4Oyk+liYQ=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk0N4Oyk+mQlg=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk0N4Oyk+nStE=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk0N4Oyk+oJr0=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk0N4Oyk+p2dM=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk0N4Oyk+qa+E=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk0N4Oyk+rD68=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk0OXsx2lH55c=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk0OXsyGlI3Sg=", + "_parent": { + "$ref": "AAAAAAFk0OXsx2lH55c=" + }, + "model": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk0OXsyGlJgjo=", + "_parent": { + "$ref": "AAAAAAFk0OXsyGlI3Sg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 197, + "top": 541, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0OXsyGlK+Ys=", + "_parent": { + "$ref": "AAAAAAFk0OXsyGlI3Sg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 197, + "top": 556, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDMemoryCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0OXsyGlL3pE=", + "_parent": { + "$ref": "AAAAAAFk0OXsyGlI3Sg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 197, + "top": 571, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0OXsyGlM+TI=", + "_parent": { + "$ref": "AAAAAAFk0OXsyGlI3Sg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1106, + "top": -2192, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 192, + "top": 536, + "width": 138, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk0OXsyGlJgjo=" + }, + "nameLabel": { + "$ref": "AAAAAAFk0OXsyGlK+Ys=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk0OXsyGlL3pE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0OXsyGlM+TI=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk0OXsyGlNF+g=", + "_parent": { + "$ref": "AAAAAAFk0OXsx2lH55c=" + }, + "model": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -553, + "top": -1096, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk0OXsyGlOlcw=", + "_parent": { + "$ref": "AAAAAAFk0OXsx2lH55c=" + }, + "model": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0OXtDGmOpvI=", + "_parent": { + "$ref": "AAAAAAFk0OXsyGlOlcw=" + }, + "model": { + "$ref": "AAAAAAFk0OSfa2QT4IA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 101, + "top": -166, + "width": 175.17626953125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(config)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0OXtDWmRrbU=", + "_parent": { + "$ref": "AAAAAAFk0OXsyGlOlcw=" + }, + "model": { + "$ref": "AAAAAAFk0OTdZGUCETU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 101, + "top": -151, + "width": 175.17626953125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+object(key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0OXtDWmUsq8=", + "_parent": { + "$ref": "AAAAAAFk0OXsyGlOlcw=" + }, + "model": { + "$ref": "AAAAAAFk0OUR7WXxHho=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 101, + "top": -136, + "width": 175.17626953125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+setObject(object, key, cost)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0OXtDmmX4Bo=", + "_parent": { + "$ref": "AAAAAAFk0OXsyGlOlcw=" + }, + "model": { + "$ref": "AAAAAAFk0OWj72fwP7o=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 101, + "top": -121, + "width": 175.17626953125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeObject(object)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0OXtDmma8us=", + "_parent": { + "$ref": "AAAAAAFk0OXsyGlOlcw=" + }, + "model": { + "$ref": "AAAAAAFk0OXRGGjfriQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 101, + "top": -106, + "width": 175.17626953125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeAllObjects()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 192, + "top": 589, + "width": 185.17626953125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk0OXsyGlPZt4=", + "_parent": { + "$ref": "AAAAAAFk0OXsx2lH55c=" + }, + "model": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -553, + "top": -1096, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk0OXsyGlQUzk=", + "_parent": { + "$ref": "AAAAAAFk0OXsx2lH55c=" + }, + "model": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -553, + "top": -1096, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 192, + "top": 536, + "width": 162, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk0OXsyGlI3Sg=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk0OXsyGlNF+g=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk0OXsyGlOlcw=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk0OXsyGlPZt4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk0OXsyGlQUzk=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk0ObJQm6XCvY=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk0ObJQm6Ygcc=", + "_parent": { + "$ref": "AAAAAAFk0ObJQm6XCvY=" + }, + "model": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk0ObJQm6ZtQQ=", + "_parent": { + "$ref": "AAAAAAFk0ObJQm6Ygcc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 136, + "top": -2536, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0ObJQm6andY=", + "_parent": { + "$ref": "AAAAAAFk0ObJQm6Ygcc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 221, + "top": 639, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDMemoryCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0ObJQm6bDKI=", + "_parent": { + "$ref": "AAAAAAFk0ObJQm6Ygcc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 221, + "top": 654, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0ObJQm6cOIs=", + "_parent": { + "$ref": "AAAAAAFk0ObJQm6Ygcc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 136, + "top": -2536, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 216, + "top": 632, + "width": 128, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk0ObJQm6ZtQQ=" + }, + "nameLabel": { + "$ref": "AAAAAAFk0ObJQm6andY=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk0ObJQm6bDKI=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0ObJQm6cOIs=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk0ObJQm6dyG8=", + "_parent": { + "$ref": "AAAAAAFk0ObJQm6XCvY=" + }, + "model": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 216, + "top": 672, + "width": 133.82373046875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk0ObJQm6eN6k=", + "_parent": { + "$ref": "AAAAAAFk0ObJQm6XCvY=" + }, + "model": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 216, + "top": 682, + "width": 133.82373046875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk0ObJQm6fcNk=", + "_parent": { + "$ref": "AAAAAAFk0ObJQm6XCvY=" + }, + "model": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 68, + "top": -1268, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk0ObJQm6gHKI=", + "_parent": { + "$ref": "AAAAAAFk0ObJQm6XCvY=" + }, + "model": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 68, + "top": -1268, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 216, + "top": 632, + "width": 128, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk0ObJQm6Ygcc=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk0ObJQm6dyG8=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk0ObJQm6eN6k=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk0ObJQm6fcNk=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk0ObJQm6gHKI=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk0OcBa3CRDns=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk0ObxVHApLxs=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk0OcBa3CSXJ4=", + "_parent": { + "$ref": "AAAAAAFk0OcBa3CRDns=" + }, + "model": { + "$ref": "AAAAAAFk0ObxVHApLxs=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk0OcBa3CTKAA=", + "_parent": { + "$ref": "AAAAAAFk0OcBa3CSXJ4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -216, + "top": -2696, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0OcBa3CU5rM=", + "_parent": { + "$ref": "AAAAAAFk0OcBa3CSXJ4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 639, + "width": 102, + "height": 13, + "autoResize": false, + "underline": false, + "text": "NSCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0OcBa3CVHRE=", + "_parent": { + "$ref": "AAAAAAFk0OcBa3CSXJ4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 654, + "width": 102, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from Foundation)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0OcBa3CWINU=", + "_parent": { + "$ref": "AAAAAAFk0OcBa3CSXJ4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -216, + "top": -2696, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 632, + "width": 112, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk0OcBa3CTKAA=" + }, + "nameLabel": { + "$ref": "AAAAAAFk0OcBa3CU5rM=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk0OcBa3CVHRE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0OcBa3CWINU=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk0OcBa3CXeCk=", + "_parent": { + "$ref": "AAAAAAFk0OcBa3CRDns=" + }, + "model": { + "$ref": "AAAAAAFk0ObxVHApLxs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 672, + "width": 128.955078125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk0OcBa3CYF7I=", + "_parent": { + "$ref": "AAAAAAFk0OcBa3CRDns=" + }, + "model": { + "$ref": "AAAAAAFk0ObxVHApLxs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 682, + "width": 128.955078125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk0OcBa3CZTX4=", + "_parent": { + "$ref": "AAAAAAFk0OcBa3CRDns=" + }, + "model": { + "$ref": "AAAAAAFk0ObxVHApLxs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -124, + "top": -1348, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk0OcBa3CaKJ0=", + "_parent": { + "$ref": "AAAAAAFk0OcBa3CRDns=" + }, + "model": { + "$ref": "AAAAAAFk0ObxVHApLxs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -124, + "top": -1348, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 632, + "width": 112, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk0OcBa3CSXJ4=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk0OcBa3CXeCk=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk0OcBa3CYF7I=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk0OcBa3CZTX4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk0OcBa3CaKJ0=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk0Ok37H+rWnk=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk0Ok37H+s7Rk=", + "_parent": { + "$ref": "AAAAAAFk0Ok37H+rWnk=" + }, + "model": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk0Ok37H+tuqY=", + "_parent": { + "$ref": "AAAAAAFk0Ok37H+s7Rk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 365, + "top": 541, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0Ok37H+u5b0=", + "_parent": { + "$ref": "AAAAAAFk0Ok37H+s7Rk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 365, + "top": 556, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDDiskCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0Ok37H+vLR0=", + "_parent": { + "$ref": "AAAAAAFk0Ok37H+s7Rk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 365, + "top": 571, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0Ok37H+w91E=", + "_parent": { + "$ref": "AAAAAAFk0Ok37H+s7Rk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -124, + "top": -2230, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 360, + "top": 536, + "width": 138, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk0Ok37H+tuqY=" + }, + "nameLabel": { + "$ref": "AAAAAAFk0Ok37H+u5b0=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk0Ok37H+vLR0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0Ok37H+w91E=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk0Ok37X+xveU=", + "_parent": { + "$ref": "AAAAAAFk0Ok37H+rWnk=" + }, + "model": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -62, + "top": -1115, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk0Ok37X+y1GE=", + "_parent": { + "$ref": "AAAAAAFk0Ok37H+rWnk=" + }, + "model": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0OmAGYIp9ik=", + "_parent": { + "$ref": "AAAAAAFk0Ok37X+y1GE=" + }, + "model": { + "$ref": "AAAAAAFk0Ol/z4IFWS0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 245, + "top": -166, + "width": 157.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(cachePath, config)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0Onk2YW0iUQ=", + "_parent": { + "$ref": "AAAAAAFk0Ok37X+y1GE=" + }, + "model": { + "$ref": "AAAAAAFk0OnkkIWQSuA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 245, + "top": -151, + "width": 157.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+containsData(key): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0OpCbIk/0SA=", + "_parent": { + "$ref": "AAAAAAFk0Ok37X+y1GE=" + }, + "model": { + "$ref": "AAAAAAFk0OpCIYkbyn4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 245, + "top": -136, + "width": 157.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+data(key): Data", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0OrYXozKw8k=", + "_parent": { + "$ref": "AAAAAAFk0Ok37X+y1GE=" + }, + "model": { + "$ref": "AAAAAAFk0OrYDIym0yM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 245, + "top": -121, + "width": 157.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+setData(data, key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0OsjwZASNSE=", + "_parent": { + "$ref": "AAAAAAFk0Ok37X+y1GE=" + }, + "model": { + "$ref": "AAAAAAFk0OsjbY/ujGE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 245, + "top": -106, + "width": 157.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeData(key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0OtX/JJO2vY=", + "_parent": { + "$ref": "AAAAAAFk0Ok37X+y1GE=" + }, + "model": { + "$ref": "AAAAAAFk0OtXrZIqqoc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 245, + "top": -91, + "width": 157.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeAllData()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0Ot0JZPhDKo=", + "_parent": { + "$ref": "AAAAAAFk0Ok37X+y1GE=" + }, + "model": { + "$ref": "AAAAAAFk0Otz15O9b20=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 245, + "top": -76, + "width": 157.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeExpiredData()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0OuY35V0c08=", + "_parent": { + "$ref": "AAAAAAFk0Ok37X+y1GE=" + }, + "model": { + "$ref": "AAAAAAFk0OuYl5VQkGk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 245, + "top": -61, + "width": 157.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cachePath(key): String", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0Ovfv5ew5s0=", + "_parent": { + "$ref": "AAAAAAFk0Ok37X+y1GE=" + }, + "model": { + "$ref": "AAAAAAFk0Ovfd5eMoXg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 245, + "top": -46, + "width": 157.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+totalCount(): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk0OxWMpvhvXE=", + "_parent": { + "$ref": "AAAAAAFk0Ok37X+y1GE=" + }, + "model": { + "$ref": "AAAAAAFk0OxV6pu94G8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 245, + "top": -31, + "width": 157.82373046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+totalSize(): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 360, + "top": 589, + "width": 167.82373046875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk0Ok37X+zsS8=", + "_parent": { + "$ref": "AAAAAAFk0Ok37H+rWnk=" + }, + "model": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -62, + "top": -1115, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk0Ok37X+0nhU=", + "_parent": { + "$ref": "AAAAAAFk0Ok37H+rWnk=" + }, + "model": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -62, + "top": -1115, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 360, + "top": 536, + "width": 162, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk0Ok37H+s7Rk=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk0Ok37X+xveU=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk0Ok37X+y1GE=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk0Ok37X+zsS8=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk0Ok37X+0nhU=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk0O0AHJ67b/Q=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk0Oy3g5480kU=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk0O0AHJ68R4A=", + "_parent": { + "$ref": "AAAAAAFk0O0AHJ67b/Q=" + }, + "model": { + "$ref": "AAAAAAFk0Oy3g5480kU=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk0O0AHJ69hP8=", + "_parent": { + "$ref": "AAAAAAFk0O0AHJ68R4A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 2, + "top": -2598, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0O0AHJ6+pE0=", + "_parent": { + "$ref": "AAAAAAFk0O0AHJ68R4A=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 381, + "top": 639, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDDiskCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0O0AHJ6/CJE=", + "_parent": { + "$ref": "AAAAAAFk0O0AHJ68R4A=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 381, + "top": 654, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk0O0AHJ7A1Qo=", + "_parent": { + "$ref": "AAAAAAFk0O0AHJ68R4A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 2, + "top": -2598, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 376, + "top": 632, + "width": 128, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk0O0AHJ69hP8=" + }, + "nameLabel": { + "$ref": "AAAAAAFk0O0AHJ6+pE0=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk0O0AHJ6/CJE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0O0AHJ7A1Qo=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk0O0AHJ7B6oA=", + "_parent": { + "$ref": "AAAAAAFk0O0AHJ67b/Q=" + }, + "model": { + "$ref": "AAAAAAFk0Oy3g5480kU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 376, + "top": 672, + "width": 133.82373046875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk0O0AHJ7CwB0=", + "_parent": { + "$ref": "AAAAAAFk0O0AHJ67b/Q=" + }, + "model": { + "$ref": "AAAAAAFk0Oy3g5480kU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 376, + "top": 682, + "width": 133.82373046875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk0O0AHJ7DvnM=", + "_parent": { + "$ref": "AAAAAAFk0O0AHJ67b/Q=" + }, + "model": { + "$ref": "AAAAAAFk0Oy3g5480kU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1, + "top": -1299, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk0O0AHJ7EitQ=", + "_parent": { + "$ref": "AAAAAAFk0O0AHJ67b/Q=" + }, + "model": { + "$ref": "AAAAAAFk0Oy3g5480kU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1, + "top": -1299, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 376, + "top": 632, + "width": 128, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk0O0AHJ68R4A=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk0O0AHJ7B6oA=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk0O0AHJ7CwB0=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk0O0AHJ7DvnM=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk0O0AHJ7EitQ=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk0O7I0qzM9Wk=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0O7I0qzN0WA=", + "_parent": { + "$ref": "AAAAAAFk0O7I0qzM9Wk=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 264, + "top": 603, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0O7I0qzM9Wk=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0O7I0qzOSBg=", + "_parent": { + "$ref": "AAAAAAFk0O7I0qzM9Wk=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 249, + "top": 603, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0O7I0qzM9Wk=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0O7I0qzPVyo=", + "_parent": { + "$ref": "AAAAAAFk0O7I0qzM9Wk=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 604, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0O7I0qzM9Wk=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk0OXsx2lH55c=" + }, + "tail": { + "$ref": "AAAAAAFk0ObJQm6XCvY=" + }, + "lineStyle": 0, + "points": "279:632;279:588", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk0O7I0qzN0WA=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk0O7I0qzOSBg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0O7I0qzPVyo=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk0O8UE69VlbA=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0O8UE69WSok=", + "_parent": { + "$ref": "AAAAAAFk0O8UE69VlbA=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 432, + "top": 603, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0O8UE69VlbA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0O8UE69XlHA=", + "_parent": { + "$ref": "AAAAAAFk0O8UE69VlbA=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 417, + "top": 603, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0O8UE69VlbA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0O8UE69Y83w=", + "_parent": { + "$ref": "AAAAAAFk0O8UE69VlbA=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 461, + "top": 604, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0O8UE69VlbA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk0Ok37H+rWnk=" + }, + "tail": { + "$ref": "AAAAAAFk0O0AHJ67b/Q=" + }, + "lineStyle": 0, + "points": "447:632;447:588", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk0O8UE69WSok=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk0O8UE69XlHA=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0O8UE69Y83w=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAFk0O+FTbdsGCE=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0O+FTbdtn8U=", + "_parent": { + "$ref": "AAAAAAFk0O+FTbdsGCE=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 166, + "top": 657, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0O+FTbdsGCE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0O+FTbduFUQ=", + "_parent": { + "$ref": "AAAAAAFk0O+FTbdsGCE=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 166, + "top": 672, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0O+FTbdsGCE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0O+FTbdv+HU=", + "_parent": { + "$ref": "AAAAAAFk0O+FTbdsGCE=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 167, + "top": 627, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0O+FTbdsGCE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk0OcBa3CRDns=" + }, + "tail": { + "$ref": "AAAAAAFk0ObJQm6XCvY=" + }, + "lineStyle": 0, + "points": "216:648;119:648", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk0O+FTbdtn8U=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk0O+FTbduFUQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0O+FTbdv+HU=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk0PADwLtOEAo=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PADwLtPZX8=", + "_parent": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 305, + "top": 480, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PADwLtQZRU=", + "_parent": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 290, + "top": 480, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PADwLtRLtw=", + "_parent": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 334, + "top": 481, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PADwLtSz+s=", + "_parent": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 305, + "top": 504, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PADwLtTEK8=", + "_parent": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 291, + "top": 501, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PADwLtUKFE=", + "_parent": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 332, + "top": 508, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PADwLtVIVU=", + "_parent": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 282, + "top": 458, + "width": 46.490234375, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "edgePosition": 0, + "underline": false, + "text": "+config", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PADwLtW4Rw=", + "_parent": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 291, + "top": 461, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PADwLtXeqU=", + "_parent": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 332, + "top": 454, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk0PADwLtYbvM=", + "_parent": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 107, + "top": 862, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk0PADwLtZevo=", + "_parent": { + "$ref": "AAAAAAFk0PADwLtOEAo=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 107, + "top": 862, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmNdXmNnpp1I=" + }, + "tail": { + "$ref": "AAAAAAFk0OXsx2lH55c=" + }, + "lineStyle": 0, + "points": "320:536;320:439", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk0PADwLtPZX8=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk0PADwLtQZRU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0PADwLtRLtw=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk0PADwLtSz+s=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk0PADwLtTEK8=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk0PADwLtUKFE=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk0PADwLtVIVU=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk0PADwLtW4Rw=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk0PADwLtXeqU=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk0PADwLtYbvM=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk0PADwLtZevo=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk0PAr0b41BE0=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PAr0b42Doc=", + "_parent": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 385, + "top": 480, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PAr0b43ZyQ=", + "_parent": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 370, + "top": 480, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PAr0b444sU=", + "_parent": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 414, + "top": 481, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PAr0b45uBI=", + "_parent": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 385, + "top": 504, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PAr0b46IzE=", + "_parent": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 371, + "top": 501, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PAr0b479/8=", + "_parent": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 412, + "top": 508, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PAr0b48/Ys=", + "_parent": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 362, + "top": 458, + "width": 46.490234375, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "edgePosition": 0, + "underline": false, + "text": "+config", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PAr0b49v7U=", + "_parent": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 371, + "top": 461, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0PAr0b4+/gE=", + "_parent": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 412, + "top": 454, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk0PAr0b4/i4o=", + "_parent": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 602, + "top": 838, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk0PAr0b5AWoA=", + "_parent": { + "$ref": "AAAAAAFk0PAr0b41BE0=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 602, + "top": 838, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmNdXmNnpp1I=" + }, + "tail": { + "$ref": "AAAAAAFk0Ok37H+rWnk=" + }, + "lineStyle": 0, + "points": "400:536;400:439", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk0PAr0b42Doc=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk0PAr0b43ZyQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0PAr0b444sU=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk0PAr0b45uBI=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk0PAr0b46IzE=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk0PAr0b479/8=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk0PAr0b48/Ys=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk0PAr0b49v7U=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk0PAr0b4+/gE=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk0PAr0b4/i4o=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk0PAr0b5AWoA=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk0Q5c9JhBKDI=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk0Q5c9Jg/0Jc=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0Q5c9ZhCJjw=", + "_parent": { + "$ref": "AAAAAAFk0Q5c9JhBKDI=" + }, + "model": { + "$ref": "AAAAAAFk0Q5c9Jg/0Jc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 91, + "top": 102, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0Q5c9JhBKDI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0Q5c9ZhDK/E=", + "_parent": { + "$ref": "AAAAAAFk0Q5c9JhBKDI=" + }, + "model": { + "$ref": "AAAAAAFk0Q5c9Jg/0Jc=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 91, + "top": 87, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0Q5c9JhBKDI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0Q5c9ZhEh/o=", + "_parent": { + "$ref": "AAAAAAFk0Q5c9JhBKDI=" + }, + "model": { + "$ref": "AAAAAAFk0Q5c9Jg/0Jc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 91, + "top": 132, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0Q5c9JhBKDI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFXmsqnFRq0kTA=" + }, + "tail": { + "$ref": "AAAAAAFUmPubFi7kzSY=" + }, + "lineStyle": 0, + "points": "91:55;91:123;360:123", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk0Q5c9ZhCJjw=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk0Q5c9ZhDK/E=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0Q5c9ZhEh/o=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk0Q/6pahtoxo=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk0Q/6pKhroeQ=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0Q/6pahuNSI=", + "_parent": { + "$ref": "AAAAAAFk0Q/6pahtoxo=" + }, + "model": { + "$ref": "AAAAAAFk0Q/6pKhroeQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 493, + "top": 132, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0Q/6pahtoxo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0Q/6pahvvVw=", + "_parent": { + "$ref": "AAAAAAFk0Q/6pahtoxo=" + }, + "model": { + "$ref": "AAAAAAFk0Q/6pKhroeQ=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 493, + "top": 147, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0Q/6pahtoxo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0Q/6pahwUqw=", + "_parent": { + "$ref": "AAAAAAFk0Q/6pahtoxo=" + }, + "model": { + "$ref": "AAAAAAFk0Q/6pKhroeQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 494, + "top": 102, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0Q/6pahtoxo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFXmsqnFRq0kTA=" + }, + "tail": { + "$ref": "AAAAAAFUmPsPJi0J5Fw=" + }, + "lineStyle": 0, + "points": "494:55;494:123;489:123", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk0Q/6pahuNSI=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk0Q/6pahvvVw=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0Q/6pahwUqw=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk0RCPR6y8NfI=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk0RCPR6y62U8=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0RCPR6y9okc=", + "_parent": { + "$ref": "AAAAAAFk0RCPR6y8NfI=" + }, + "model": { + "$ref": "AAAAAAFk0RCPR6y62U8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 132, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0RCPR6y8NfI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0RCPR6y+PPE=", + "_parent": { + "$ref": "AAAAAAFk0RCPR6y8NfI=" + }, + "model": { + "$ref": "AAAAAAFk0RCPR6y62U8=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 147, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0RCPR6y8NfI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0RCPR6y/G5A=", + "_parent": { + "$ref": "AAAAAAFk0RCPR6y8NfI=" + }, + "model": { + "$ref": "AAAAAAFk0RCPR6y62U8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 670, + "top": 102, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0RCPR6y8NfI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFXmsqnFRq0kTA=" + }, + "tail": { + "$ref": "AAAAAAFUmPnxoSwmlwM=" + }, + "lineStyle": 0, + "points": "670:55;670:123;489:123", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk0RCPR6y9okc=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk0RCPR6y+PPE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0RCPR6y/G5A=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk0RH/JbQMCBE=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk0RH/JbQKgpI=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0RH/JbQN0PQ=", + "_parent": { + "$ref": "AAAAAAFk0RH/JbQMCBE=" + }, + "model": { + "$ref": "AAAAAAFk0RH/JbQKgpI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 92, + "top": 136, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0RH/JbQMCBE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0RH/JbQO2rM=", + "_parent": { + "$ref": "AAAAAAFk0RH/JbQMCBE=" + }, + "model": { + "$ref": "AAAAAAFk0RH/JbQKgpI=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 107, + "top": 136, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0RH/JbQMCBE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0RH/JbQPvRU=", + "_parent": { + "$ref": "AAAAAAFk0RH/JbQMCBE=" + }, + "model": { + "$ref": "AAAAAAFk0RH/JbQKgpI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 63, + "top": 137, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0RH/JbQMCBE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFkzO7AJ0YXKM0=" + }, + "tail": { + "$ref": "AAAAAAFXmsqnFRq0kTA=" + }, + "lineStyle": 0, + "points": "360:143;78:143;78:144", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk0RH/JbQN0PQ=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk0RH/JbQO2rM=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0RH/JbQPvRU=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk0RKU97ihrAY=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk0RKU97ifqxY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0RKU97ii404=", + "_parent": { + "$ref": "AAAAAAFk0RKU97ihrAY=" + }, + "model": { + "$ref": "AAAAAAFk0RKU97ifqxY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 446, + "top": 172, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0RKU97ihrAY=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0RKU97ij8oQ=", + "_parent": { + "$ref": "AAAAAAFk0RKU97ihrAY=" + }, + "model": { + "$ref": "AAAAAAFk0RKU97ifqxY=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 461, + "top": 172, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk0RKU97ihrAY=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk0RKU97ikv2Q=", + "_parent": { + "$ref": "AAAAAAFk0RKU97ihrAY=" + }, + "model": { + "$ref": "AAAAAAFk0RKU97ifqxY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 417, + "top": 173, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk0RKU97ihrAY=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUmMuDNcmaKIo=" + }, + "tail": { + "$ref": "AAAAAAFXmsqnFRq0kTA=" + }, + "lineStyle": 0, + "points": "432:143;432:216", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk0RKU97ii404=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk0RKU97ij8oQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk0RKU97ikv2Q=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk6+vKjo5a2wA=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk6+vKjo5YRUw=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk6+vKjo5bJp0=", + "_parent": { + "$ref": "AAAAAAFk6+vKjo5a2wA=" + }, + "model": { + "$ref": "AAAAAAFk6+vKjo5YRUw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 447, + "top": 179, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk6+vKjo5a2wA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk6+vKjo5caY0=", + "_parent": { + "$ref": "AAAAAAFk6+vKjo5a2wA=" + }, + "model": { + "$ref": "AAAAAAFk6+vKjo5YRUw=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 447, + "top": 194, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk6+vKjo5a2wA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk6+vKjo5dJDE=", + "_parent": { + "$ref": "AAAAAAFk6+vKjo5a2wA=" + }, + "model": { + "$ref": "AAAAAAFk6+vKjo5YRUw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 448, + "top": 149, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk6+vKjo5a2wA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFkzO7AJ0YXKM0=" + }, + "tail": { + "$ref": "AAAAAAFUmMuDNcmaKIo=" + }, + "lineStyle": 0, + "points": "448:216;448:170;149:170", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk6+vKjo5bJp0=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk6+vKjo5caY0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk6+vKjo5dJDE=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7AANcUb769w=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7AANcUb8kHE=", + "_parent": { + "$ref": "AAAAAAFk7AANcUb769w=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7AANcUb9U5Q=", + "_parent": { + "$ref": "AAAAAAFk7AANcUb8kHE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -918, + "top": -660, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7AANcUb+31o=", + "_parent": { + "$ref": "AAAAAAFk7AANcUb8kHE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 925, + "top": 375, + "width": 159, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageLoadersManager", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7AANcUb/rmc=", + "_parent": { + "$ref": "AAAAAAFk7AANcUb8kHE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 925, + "top": 390, + "width": 159, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7AANckcA5E0=", + "_parent": { + "$ref": "AAAAAAFk7AANcUb8kHE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -918, + "top": -660, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 920, + "top": 368, + "width": 169, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7AANcUb9U5Q=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7AANcUb+31o=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7AANcUb/rmc=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7AANckcA5E0=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7AANckcBDM0=", + "_parent": { + "$ref": "AAAAAAFk7AANcUb769w=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7AANm0c/0CU=", + "_parent": { + "$ref": "AAAAAAFk7AANckcBDM0=" + }, + "model": { + "$ref": "AAAAAAFkzOIg/+78rRg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 637, + "top": -51, + "width": 209.37744140625, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedManager", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7AANnEdCaZ8=", + "_parent": { + "$ref": "AAAAAAFk7AANckcBDM0=" + }, + "model": { + "$ref": "AAAAAAFkzOOPjva3FJM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 637, + "top": -36, + "width": 209.37744140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+loaders: Array ", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 920, + "top": 408, + "width": 219.37744140625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7AANckcC9FU=", + "_parent": { + "$ref": "AAAAAAFk7AANcUb769w=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7AANnEdFBYA=", + "_parent": { + "$ref": "AAAAAAFk7AANckcC9FU=" + }, + "model": { + "$ref": "AAAAAAFkzOP6yPhv64w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 637, + "top": -13, + "width": 209.37744140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+addLoader()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7AANnUdIOFI=", + "_parent": { + "$ref": "AAAAAAFk7AANckcC9FU=" + }, + "model": { + "$ref": "AAAAAAFkzOQxGfm6yKY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 637, + "top": 2, + "width": 209.37744140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeLoader()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 920, + "top": 446, + "width": 219.37744140625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7AANckcDKsY=", + "_parent": { + "$ref": "AAAAAAFk7AANcUb769w=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -459, + "top": -330, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7AANckcEYyY=", + "_parent": { + "$ref": "AAAAAAFk7AANcUb769w=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -459, + "top": -330, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 920, + "top": 368, + "width": 169, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7AANcUb8kHE=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7AANckcBDM0=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7AANckcC9FU=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7AANckcDKsY=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7AANckcEYyY=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7AFZv1iyb28=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7AFZvlix+G0=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7AFZv1izR1M=", + "_parent": { + "$ref": "AAAAAAFk7AFZv1iyb28=" + }, + "model": { + "$ref": "AAAAAAFk7AFZvlix+G0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1003, + "top": 339, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7AFZv1iyb28=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7AFZv1i0KoU=", + "_parent": { + "$ref": "AAAAAAFk7AFZv1iyb28=" + }, + "model": { + "$ref": "AAAAAAFk7AFZvlix+G0=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1003, + "top": 354, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7AFZv1iyb28=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7AFZv1i1E0g=", + "_parent": { + "$ref": "AAAAAAFk7AFZv1iyb28=" + }, + "model": { + "$ref": "AAAAAAFk7AFZvlix+G0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1004, + "top": 309, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7AFZv1iyb28=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFky2+2+WTD+rs=" + }, + "tail": { + "$ref": "AAAAAAFk7AANcUb769w=" + }, + "lineStyle": 0, + "points": "1004:368;1004:330;641:330", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7AFZv1izR1M=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7AFZv1i0KoU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7AFZv1i1E0g=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7AJFfl1wqqg=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7AJFfl1xUIk=", + "_parent": { + "$ref": "AAAAAAFk7AJFfl1wqqg=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7AJFf11ysn4=", + "_parent": { + "$ref": "AAAAAAFk7AJFfl1xUIk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -134, + "top": -1550, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7AJFf11zqjI=", + "_parent": { + "$ref": "AAAAAAFk7AJFfl1xUIk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 407, + "width": 154, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCachesManager", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7AJFf110jLY=", + "_parent": { + "$ref": "AAAAAAFk7AJFfl1xUIk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 422, + "width": 154, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7AJFf111+mo=", + "_parent": { + "$ref": "AAAAAAFk7AJFfl1xUIk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -134, + "top": -1550, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 400, + "width": 164, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7AJFf11ysn4=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7AJFf11zqjI=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7AJFf110jLY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7AJFf111+mo=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7AJFf112b2U=", + "_parent": { + "$ref": "AAAAAAFk7AJFfl1wqqg=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7ALOo2YPWYA=", + "_parent": { + "$ref": "AAAAAAFk7AJFf112b2U=" + }, + "model": { + "$ref": "AAAAAAFk7ALOcGXu/S8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 13, + "width": 200.82080078125, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedManager", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7AOZ428inSI=", + "_parent": { + "$ref": "AAAAAAFk7AJFf112b2U=" + }, + "model": { + "$ref": "AAAAAAFk7AOZr28Bcso=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 28, + "width": 200.82080078125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+caches: Array ", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7AMCtGf3iR8=", + "_parent": { + "$ref": "AAAAAAFk7AJFf112b2U=" + }, + "model": { + "$ref": "AAAAAAFk7AMCg2fWSP0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 43, + "width": 200.82080078125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+queryOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7AMfLGlmgKY=", + "_parent": { + "$ref": "AAAAAAFk7AJFf112b2U=" + }, + "model": { + "$ref": "AAAAAAFk7AMe/WlFG7c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 58, + "width": 200.82080078125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+storeOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7ANGlmrV8/w=", + "_parent": { + "$ref": "AAAAAAFk7AJFf112b2U=" + }, + "model": { + "$ref": "AAAAAAFk7ANGZ2q0x2Q=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 73, + "width": 200.82080078125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7ANgEGxE+Wo=", + "_parent": { + "$ref": "AAAAAAFk7AJFf112b2U=" + }, + "model": { + "$ref": "AAAAAAFk7ANfz2wjKJg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 88, + "width": 200.82080078125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+containsOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7AN7Vm2zvpc=", + "_parent": { + "$ref": "AAAAAAFk7AJFf112b2U=" + }, + "model": { + "$ref": "AAAAAAFk7AN7JG2S4JE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 103, + "width": 200.82080078125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+clearOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 440, + "width": 210.82080078125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7AJFf113fhc=", + "_parent": { + "$ref": "AAAAAAFk7AJFfl1wqqg=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7AQxOXaTdhk=", + "_parent": { + "$ref": "AAAAAAFk7AJFf113fhc=" + }, + "model": { + "$ref": "AAAAAAFk7AQw/nZyZkk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 126, + "width": 200.82080078125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+addCache()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7ARMBXgCZ5A=", + "_parent": { + "$ref": "AAAAAAFk7AJFf113fhc=" + }, + "model": { + "$ref": "AAAAAAFk7ARL1nfhIfg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 141, + "width": 200.82080078125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeCache()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 553, + "width": 210.82080078125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7AJFf114RsY=", + "_parent": { + "$ref": "AAAAAAFk7AJFfl1wqqg=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -67, + "top": -775, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7AJFgF153i4=", + "_parent": { + "$ref": "AAAAAAFk7AJFfl1wqqg=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -67, + "top": -775, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 400, + "width": 164, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7AJFfl1xUIk=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7AJFf112b2U=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7AJFf113fhc=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7AJFf114RsY=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7AJFgF153i4=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7Ae0KqF1+eo=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7Ae0KaF0uoo=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7Ae0KqF2y6w=", + "_parent": { + "$ref": "AAAAAAFk7Ae0KqF1+eo=" + }, + "model": { + "$ref": "AAAAAAFk7Ae0KaF0uoo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 89, + "top": 309, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7Ae0KqF1+eo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7Ae0KqF3Jdo=", + "_parent": { + "$ref": "AAAAAAFk7Ae0KqF1+eo=" + }, + "model": { + "$ref": "AAAAAAFk7Ae0KaF0uoo=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 89, + "top": 294, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7Ae0KqF1+eo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7Ae0KqF4BmQ=", + "_parent": { + "$ref": "AAAAAAFk7Ae0KqF1+eo=" + }, + "model": { + "$ref": "AAAAAAFk7Ae0KaF0uoo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 89, + "top": 339, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7Ae0KqF1+eo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFkzOeFlQjK4RM=" + }, + "tail": { + "$ref": "AAAAAAFk7AJFfl1wqqg=" + }, + "lineStyle": 0, + "points": "89:400;89:330;288:330", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7Ae0KqF2y6w=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7Ae0KqF3Jdo=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7Ae0KqF4BmQ=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk7AxBZNKgMek=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7AxBZdKhn88=", + "_parent": { + "$ref": "AAAAAAFk7AxBZNKgMek=" + }, + "model": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7AxBZdKiBFk=", + "_parent": { + "$ref": "AAAAAAFk7AxBZdKhn88=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 834, + "width": 186, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7AxBZdKjgUg=", + "_parent": { + "$ref": "AAAAAAFk7AxBZdKhn88=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 849, + "width": 186, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageCacheKeyFilter", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7AxBZdKk9X4=", + "_parent": { + "$ref": "AAAAAAFk7AxBZdKhn88=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 864, + "width": 186, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7AxBZdKlGsk=", + "_parent": { + "$ref": "AAAAAAFk7AxBZdKhn88=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -174, + "top": -2528, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 829, + "width": 196, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7AxBZdKiBFk=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7AxBZdKjgUg=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7AxBZdKk9X4=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7AxBZdKlGsk=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7AxBZdKmKZw=", + "_parent": { + "$ref": "AAAAAAFk7AxBZNKgMek=" + }, + "model": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -87, + "top": -1264, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7AxBZtKnD5Q=", + "_parent": { + "$ref": "AAAAAAFk7AxBZNKgMek=" + }, + "model": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7AyMptStw7g=", + "_parent": { + "$ref": "AAAAAAFk7AxBZtKnD5Q=" + }, + "model": { + "$ref": "AAAAAAFk7AyMbdSMtVQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -196, + "width": 219.58642578125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cacheKey(url): String", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 882, + "width": 229.58642578125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7AxBZtKo/q4=", + "_parent": { + "$ref": "AAAAAAFk7AxBZNKgMek=" + }, + "model": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -87, + "top": -1264, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7AxBZtKpxkU=", + "_parent": { + "$ref": "AAAAAAFk7AxBZNKgMek=" + }, + "model": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -87, + "top": -1264, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 829, + "width": 220, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7AxBZdKhn88=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7AxBZdKmKZw=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7AxBZtKnD5Q=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7AxBZtKo/q4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7AxBZtKpxkU=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7A0gPdfSU3A=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7Aze6dcrc1c=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7A0gPtfT0RI=", + "_parent": { + "$ref": "AAAAAAFk7A0gPdfSU3A=" + }, + "model": { + "$ref": "AAAAAAFk7Aze6dcrc1c=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7A0gPtfUTRU=", + "_parent": { + "$ref": "AAAAAAFk7A0gPtfT0RI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 272, + "top": -2802, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7A0gPtfVQkA=", + "_parent": { + "$ref": "AAAAAAFk7A0gPtfT0RI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 839, + "width": 176, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageCacheKeyFilter", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7A0gPtfW774=", + "_parent": { + "$ref": "AAAAAAFk7A0gPtfT0RI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 854, + "width": 176, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7A0gPtfXm3Y=", + "_parent": { + "$ref": "AAAAAAFk7A0gPtfT0RI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 272, + "top": -2802, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 280, + "top": 832, + "width": 186, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7A0gPtfUTRU=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7A0gPtfVQkA=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7A0gPtfW774=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7A0gPtfXm3Y=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7A0gPtfY5I4=", + "_parent": { + "$ref": "AAAAAAFk7A0gPdfSU3A=" + }, + "model": { + "$ref": "AAAAAAFk7Aze6dcrc1c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 280, + "top": 872, + "width": 195.58642578125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7A0gPtfZJyY=", + "_parent": { + "$ref": "AAAAAAFk7A0gPdfSU3A=" + }, + "model": { + "$ref": "AAAAAAFk7Aze6dcrc1c=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7A2zjduwFr0=", + "_parent": { + "$ref": "AAAAAAFk7A0gPtfZJyY=" + }, + "model": { + "$ref": "AAAAAAFk7A2zWNuPpjU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 261, + "top": -193, + "width": 185.58642578125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(block)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 280, + "top": 882, + "width": 195.58642578125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7A0gP9fanyA=", + "_parent": { + "$ref": "AAAAAAFk7A0gPdfSU3A=" + }, + "model": { + "$ref": "AAAAAAFk7Aze6dcrc1c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 136, + "top": -1401, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7A0gP9fbNgo=", + "_parent": { + "$ref": "AAAAAAFk7A0gPdfSU3A=" + }, + "model": { + "$ref": "AAAAAAFk7Aze6dcrc1c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 136, + "top": -1401, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 280, + "top": 832, + "width": 186, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7A0gPtfT0RI=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7A0gPtfY5I4=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7A0gPtfZJyY=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7A0gP9fanyA=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7A0gP9fbNgo=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7A02MtlDKaw=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7A02MdlCa2M=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7A02MtlEnB0=", + "_parent": { + "$ref": "AAAAAAFk7A02MtlDKaw=" + }, + "model": { + "$ref": "AAAAAAFk7A02MdlCa2M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 252, + "top": 862, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7A02MtlDKaw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7A02MtlFPZs=", + "_parent": { + "$ref": "AAAAAAFk7A02MtlDKaw=" + }, + "model": { + "$ref": "AAAAAAFk7A02MdlCa2M=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 252, + "top": 877, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7A02MtlDKaw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7A02MtlGgEI=", + "_parent": { + "$ref": "AAAAAAFk7A02MtlDKaw=" + }, + "model": { + "$ref": "AAAAAAFk7A02MdlCa2M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 253, + "top": 832, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7A02MtlDKaw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7AxBZNKgMek=" + }, + "tail": { + "$ref": "AAAAAAFk7A0gPdfSU3A=" + }, + "lineStyle": 0, + "points": "280:853;227:853", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7A02MtlEnB0=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7A02MtlFPZs=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7A02MtlGgEI=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk7A65DOHb9GA=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7A65DOHcbdE=", + "_parent": { + "$ref": "AAAAAAFk7A65DOHb9GA=" + }, + "model": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7A65DOHd11Q=", + "_parent": { + "$ref": "AAAAAAFk7A65DOHcbdE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 914, + "width": 190, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7A65DOHeAXI=", + "_parent": { + "$ref": "AAAAAAFk7A65DOHcbdE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 929, + "width": 190, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageCacheSerializer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7A65DOHfZjw=", + "_parent": { + "$ref": "AAAAAAFk7A65DOHcbdE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 944, + "width": 190, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7A65DOHgYSM=", + "_parent": { + "$ref": "AAAAAAFk7A65DOHcbdE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -808, + "top": -2774, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 909, + "width": 200, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7A65DOHd11Q=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7A65DOHeAXI=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7A65DOHfZjw=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7A65DOHgYSM=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7A65DOHhn8Q=", + "_parent": { + "$ref": "AAAAAAFk7A65DOHb9GA=" + }, + "model": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -404, + "top": -1387, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7A65DeHiAFk=", + "_parent": { + "$ref": "AAAAAAFk7A65DOHb9GA=" + }, + "model": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7A8q1eQj2FE=", + "_parent": { + "$ref": "AAAAAAFk7A65DeHiAFk=" + }, + "model": { + "$ref": "AAAAAAFk7A8qouQCrJM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -116, + "width": 257.78466796875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cacheData(image, data, imageURL): Data", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 962, + "width": 267.78466796875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7A65DeHj/UU=", + "_parent": { + "$ref": "AAAAAAFk7A65DOHb9GA=" + }, + "model": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -404, + "top": -1387, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7A65DeHkGj0=", + "_parent": { + "$ref": "AAAAAAFk7A65DOHb9GA=" + }, + "model": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -404, + "top": -1387, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 909, + "width": 224, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7A65DOHcbdE=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7A65DOHhn8Q=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7A65DeHiAFk=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7A65DeHj/UU=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7A65DeHkGj0=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7BC8iuqEcdw=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7BCTH+oZOBE=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7BC8iuqFLMk=", + "_parent": { + "$ref": "AAAAAAFk7BC8iuqEcdw=" + }, + "model": { + "$ref": "AAAAAAFk7BCTH+oZOBE=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7BC8i+qG1ug=", + "_parent": { + "$ref": "AAAAAAFk7BC8iuqFLMk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -240, + "top": -3004, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BC8i+qH0mQ=", + "_parent": { + "$ref": "AAAAAAFk7BC8iuqFLMk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 919, + "width": 180, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageCacheSerializer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BC8i+qIr88=", + "_parent": { + "$ref": "AAAAAAFk7BC8iuqFLMk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 934, + "width": 180, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BC8i+qJQRg=", + "_parent": { + "$ref": "AAAAAAFk7BC8iuqFLMk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -240, + "top": -3004, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 280, + "top": 912, + "width": 190, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7BC8i+qG1ug=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7BC8i+qH0mQ=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7BC8i+qIr88=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7BC8i+qJQRg=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7BC8i+qKgx0=", + "_parent": { + "$ref": "AAAAAAFk7BC8iuqEcdw=" + }, + "model": { + "$ref": "AAAAAAFk7BCTH+oZOBE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 280, + "top": 952, + "width": 198.931640625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7BC8i+qLyyM=", + "_parent": { + "$ref": "AAAAAAFk7BC8iuqEcdw=" + }, + "model": { + "$ref": "AAAAAAFk7BCTH+oZOBE=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7BE9pu774VI=", + "_parent": { + "$ref": "AAAAAAFk7BC8i+qLyyM=" + }, + "model": { + "$ref": "AAAAAAFk7BE9ae7ahlI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 261, + "top": -113, + "width": 188.931640625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(block)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 280, + "top": 962, + "width": 198.931640625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7BC8i+qM0dE=", + "_parent": { + "$ref": "AAAAAAFk7BC8iuqEcdw=" + }, + "model": { + "$ref": "AAAAAAFk7BCTH+oZOBE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -120, + "top": -1502, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7BC8jOqNr9Q=", + "_parent": { + "$ref": "AAAAAAFk7BC8iuqEcdw=" + }, + "model": { + "$ref": "AAAAAAFk7BCTH+oZOBE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -120, + "top": -1502, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 280, + "top": 912, + "width": 190, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7BC8iuqFLMk=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7BC8i+qKgx0=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7BC8i+qLyyM=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7BC8i+qM0dE=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7BC8jOqNr9Q=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7BDJZOsjGRI=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7BDJZOsigsQ=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7BDJZOskokg=", + "_parent": { + "$ref": "AAAAAAFk7BDJZOsjGRI=" + }, + "model": { + "$ref": "AAAAAAFk7BDJZOsigsQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 254, + "top": 937, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7BDJZOsjGRI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7BDJZeslfEU=", + "_parent": { + "$ref": "AAAAAAFk7BDJZOsjGRI=" + }, + "model": { + "$ref": "AAAAAAFk7BDJZOsigsQ=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 254, + "top": 952, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7BDJZOsjGRI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7BDJZesmZmQ=", + "_parent": { + "$ref": "AAAAAAFk7BDJZOsjGRI=" + }, + "model": { + "$ref": "AAAAAAFk7BDJZOsigsQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 255, + "top": 907, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7BDJZOsjGRI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7A65DOHb9GA=" + }, + "tail": { + "$ref": "AAAAAAFk7BC8iuqEcdw=" + }, + "lineStyle": 0, + "points": "280:928;231:928", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7BDJZOskokg=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7BDJZeslfEU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7BDJZesmZmQ=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk7BH3rPEP74Y=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7BH3rfEQ8LE=", + "_parent": { + "$ref": "AAAAAAFk7BH3rPEP74Y=" + }, + "model": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7BH3rfERjNk=", + "_parent": { + "$ref": "AAAAAAFk7BH3rfEQ8LE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 978, + "width": 217, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BH3rfES0FU=", + "_parent": { + "$ref": "AAAAAAFk7BH3rfEQ8LE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 993, + "width": 217, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageTransformer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BH3rfETqno=", + "_parent": { + "$ref": "AAAAAAFk7BH3rfEQ8LE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 1008, + "width": 217, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage - Transformers)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BH3rfEUqFA=", + "_parent": { + "$ref": "AAAAAAFk7BH3rfEQ8LE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1514, + "top": -2656, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 973, + "width": 227, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7BH3rfERjNk=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7BH3rfES0FU=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7BH3rfETqno=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7BH3rfEUqFA=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7BH3rfEVJdg=", + "_parent": { + "$ref": "AAAAAAFk7BH3rPEP74Y=" + }, + "model": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -757, + "top": -1328, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7BH3rvEWbcY=", + "_parent": { + "$ref": "AAAAAAFk7BH3rPEP74Y=" + }, + "model": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7BJFnPOTVVc=", + "_parent": { + "$ref": "AAAAAAFk7BH3rvEWbcY=" + }, + "model": { + "$ref": "AAAAAAFk7BJFY/NyunQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -148, + "width": 256.66943359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+transformerKey(): String", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7BKJyvXZKu0=", + "_parent": { + "$ref": "AAAAAAFk7BH3rvEWbcY=" + }, + "model": { + "$ref": "AAAAAAFk7BKJjfW40dE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": -133, + "width": 256.66943359375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+transformedImage(image, key): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 1026, + "width": 266.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7BH3rvEXjJM=", + "_parent": { + "$ref": "AAAAAAFk7BH3rPEP74Y=" + }, + "model": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -757, + "top": -1328, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7BH3rvEYJ04=", + "_parent": { + "$ref": "AAAAAAFk7BH3rPEP74Y=" + }, + "model": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -757, + "top": -1328, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 973, + "width": 251, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7BH3rfEQ8LE=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7BH3rfEVJdg=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7BH3rvEWbcY=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7BH3rvEXjJM=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7BH3rvEYJ04=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7BOaWPrCtDM=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7BOaWfrDedY=", + "_parent": { + "$ref": "AAAAAAFk7BOaWPrCtDM=" + }, + "model": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7BOaWfrEtlQ=", + "_parent": { + "$ref": "AAAAAAFk7BOaWfrDedY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -802, + "top": -2894, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BOaWvrFg8w=", + "_parent": { + "$ref": "AAAAAAFk7BOaWfrDedY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": 980, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImagePipelineTransformer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BOaWvrGtyI=", + "_parent": { + "$ref": "AAAAAAFk7BOaWfrDedY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": 995, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage - Transformers)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BOaWvrH9qE=", + "_parent": { + "$ref": "AAAAAAFk7BOaWfrDedY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -802, + "top": -2894, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 973, + "width": 217, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7BOaWfrEtlQ=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7BOaWvrFg8w=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7BOaWvrGtyI=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7BOaWvrH9qE=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7BOaWvrITRA=", + "_parent": { + "$ref": "AAAAAAFk7BOaWPrCtDM=" + }, + "model": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7BQPQ/6DBe0=", + "_parent": { + "$ref": "AAAAAAFk7BOaWvrITRA=" + }, + "model": { + "$ref": "AAAAAAFk7BQPCv5irlw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": -161, + "width": 279.90625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+transformers: Array ", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 1013, + "width": 289.90625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7BOaWvrJ59Q=", + "_parent": { + "$ref": "AAAAAAFk7BOaWPrCtDM=" + }, + "model": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7BRd0wBrr+Y=", + "_parent": { + "$ref": "AAAAAAFk7BOaWvrJ59Q=" + }, + "model": { + "$ref": "AAAAAAFk7BRdnQBKmBE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": -138, + "width": 279.90625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(transformers)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 1036, + "width": 289.90625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7BOaW/rKuNA=", + "_parent": { + "$ref": "AAAAAAFk7BOaWPrCtDM=" + }, + "model": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -401, + "top": -1447, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7BOaW/rL93M=", + "_parent": { + "$ref": "AAAAAAFk7BOaWPrCtDM=" + }, + "model": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -401, + "top": -1447, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 304, + "top": 973, + "width": 217, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7BOaWfrDedY=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7BOaWvrITRA=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7BOaWvrJ59Q=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7BOaW/rKuNA=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7BOaW/rL93M=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7BOsyfu75C0=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7BOsyPu6CB8=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7BOsyfu88lA=", + "_parent": { + "$ref": "AAAAAAFk7BOsyfu75C0=" + }, + "model": { + "$ref": "AAAAAAFk7BOsyPu6CB8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 217, + "top": 981, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7BOsyfu75C0=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7BOsyfu9P+4=", + "_parent": { + "$ref": "AAAAAAFk7BOsyfu75C0=" + }, + "model": { + "$ref": "AAAAAAFk7BOsyPu6CB8=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 217, + "top": 996, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7BOsyfu75C0=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7BOsyfu+fr4=", + "_parent": { + "$ref": "AAAAAAFk7BOsyfu75C0=" + }, + "model": { + "$ref": "AAAAAAFk7BOsyPu6CB8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 218, + "top": 951, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7BOsyfu75C0=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7BH3rPEP74Y=" + }, + "tail": { + "$ref": "AAAAAAFk7BOaWPrCtDM=" + }, + "lineStyle": 0, + "points": "304:973;304:972;133:972;133:973", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7BOsyfu88lA=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7BOsyfu9P+4=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7BOsyfu+fr4=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7BxkFEpIXos=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7BbYDRkPcZw=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7BxkFEpJgHA=", + "_parent": { + "$ref": "AAAAAAFk7BxkFEpIXos=" + }, + "model": { + "$ref": "AAAAAAFk7BbYDRkPcZw=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7BxkFUpK1Mw=", + "_parent": { + "$ref": "AAAAAAFk7BxkFEpJgHA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -44, + "top": -2494, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BxkFUpLWRs=", + "_parent": { + "$ref": "AAAAAAFk7BxkFEpJgHA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": 1031, + "width": 215, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageRoundCornerTransformer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BxkFUpMe5A=", + "_parent": { + "$ref": "AAAAAAFk7BxkFEpJgHA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": 1046, + "width": 215, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage - Transformers)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BxkFUpN2mg=", + "_parent": { + "$ref": "AAAAAAFk7BxkFEpJgHA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -44, + "top": -2494, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 1024, + "width": 225, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7BxkFUpK1Mw=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7BxkFUpLWRs=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7BxkFUpMe5A=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7BxkFUpN2mg=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7BxkFUpOu9s=", + "_parent": { + "$ref": "AAAAAAFk7BxkFEpIXos=" + }, + "model": { + "$ref": "AAAAAAFk7BbYDRkPcZw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 1064, + "width": 241.130859375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7BxkFUpPJ+A=", + "_parent": { + "$ref": "AAAAAAFk7BxkFEpIXos=" + }, + "model": { + "$ref": "AAAAAAFk7BbYDRkPcZw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 1074, + "width": 241.130859375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7BxkFkpQcEE=", + "_parent": { + "$ref": "AAAAAAFk7BxkFEpIXos=" + }, + "model": { + "$ref": "AAAAAAFk7BbYDRkPcZw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -22, + "top": -1247, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7BxkFkpRmr8=", + "_parent": { + "$ref": "AAAAAAFk7BxkFEpIXos=" + }, + "model": { + "$ref": "AAAAAAFk7BbYDRkPcZw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -22, + "top": -1247, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 304, + "top": 1024, + "width": 225, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7BxkFEpJgHA=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7BxkFUpOu9s=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7BxkFUpPJ+A=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7BxkFkpQcEE=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7BxkFkpRmr8=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7Bx/j0v2QMc=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7Bb86xmLb4E=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7Bx/j0v32vU=", + "_parent": { + "$ref": "AAAAAAFk7Bx/j0v2QMc=" + }, + "model": { + "$ref": "AAAAAAFk7Bb86xmLb4E=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7Bx/j0v4++Q=", + "_parent": { + "$ref": "AAAAAAFk7Bx/j0v32vU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -10, + "top": -2530, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7Bx/kEv56nA=", + "_parent": { + "$ref": "AAAAAAFk7Bx/j0v32vU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": 1079, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageResizingTransformer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7Bx/kEv6Kqs=", + "_parent": { + "$ref": "AAAAAAFk7Bx/j0v32vU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": 1094, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage - Transformers)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7Bx/kEv72Sk=", + "_parent": { + "$ref": "AAAAAAFk7Bx/j0v32vU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -10, + "top": -2530, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 1072, + "width": 217, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7Bx/j0v4++Q=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7Bx/kEv56nA=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7Bx/kEv6Kqs=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7Bx/kEv72Sk=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7Bx/kEv8s24=", + "_parent": { + "$ref": "AAAAAAFk7Bx/j0v2QMc=" + }, + "model": { + "$ref": "AAAAAAFk7Bb86xmLb4E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 1112, + "width": 232.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7Bx/kEv9uzo=", + "_parent": { + "$ref": "AAAAAAFk7Bx/j0v2QMc=" + }, + "model": { + "$ref": "AAAAAAFk7Bb86xmLb4E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 1122, + "width": 232.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7Bx/kUv+OQE=", + "_parent": { + "$ref": "AAAAAAFk7Bx/j0v2QMc=" + }, + "model": { + "$ref": "AAAAAAFk7Bb86xmLb4E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -5, + "top": -1265, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7Bx/kUv/FJU=", + "_parent": { + "$ref": "AAAAAAFk7Bx/j0v2QMc=" + }, + "model": { + "$ref": "AAAAAAFk7Bb86xmLb4E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -5, + "top": -1265, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 304, + "top": 1072, + "width": 217, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7Bx/j0v32vU=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7Bx/kEv8s24=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7Bx/kEv9uzo=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7Bx/kUv+OQE=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7Bx/kUv/FJU=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7ByM3UyzV2E=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7Bce7hoHimk=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7ByM3Uy0FUU=", + "_parent": { + "$ref": "AAAAAAFk7ByM3UyzV2E=" + }, + "model": { + "$ref": "AAAAAAFk7Bce7hoHimk=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7ByM3Uy1SoI=", + "_parent": { + "$ref": "AAAAAAFk7ByM3Uy0FUU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -848, + "top": -2288, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7ByM3Uy2TzA=", + "_parent": { + "$ref": "AAAAAAFk7ByM3Uy0FUU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": 1127, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCroppingTransformer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7ByM3Uy3ZfY=", + "_parent": { + "$ref": "AAAAAAFk7ByM3Uy0FUU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": 1142, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage - Transformers)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7ByM3Uy48ko=", + "_parent": { + "$ref": "AAAAAAFk7ByM3Uy0FUU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -848, + "top": -2288, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 1120, + "width": 217, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7ByM3Uy1SoI=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7ByM3Uy2TzA=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7ByM3Uy3ZfY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7ByM3Uy48ko=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7ByM3Uy5cHc=", + "_parent": { + "$ref": "AAAAAAFk7ByM3UyzV2E=" + }, + "model": { + "$ref": "AAAAAAFk7Bce7hoHimk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 1160, + "width": 232.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7ByM3ky64aU=", + "_parent": { + "$ref": "AAAAAAFk7ByM3UyzV2E=" + }, + "model": { + "$ref": "AAAAAAFk7Bce7hoHimk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 1170, + "width": 232.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7ByM3ky7YeA=", + "_parent": { + "$ref": "AAAAAAFk7ByM3UyzV2E=" + }, + "model": { + "$ref": "AAAAAAFk7Bce7hoHimk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -424, + "top": -1144, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7ByM3ky8dMo=", + "_parent": { + "$ref": "AAAAAAFk7ByM3UyzV2E=" + }, + "model": { + "$ref": "AAAAAAFk7Bce7hoHimk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -424, + "top": -1144, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 304, + "top": 1120, + "width": 217, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7ByM3Uy0FUU=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7ByM3Uy5cHc=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7ByM3ky64aU=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7ByM3ky7YeA=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7ByM3ky8dMo=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7ByzgE5i8C0=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7BhADB1EoQk=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7ByzgE5ji+4=", + "_parent": { + "$ref": "AAAAAAFk7ByzgE5i8C0=" + }, + "model": { + "$ref": "AAAAAAFk7BhADB1EoQk=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7ByzgE5kSiU=", + "_parent": { + "$ref": "AAAAAAFk7ByzgE5ji+4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -816, + "top": -2442, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7ByzgE5lggk=", + "_parent": { + "$ref": "AAAAAAFk7ByzgE5ji+4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": 1175, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageFlippingTransformer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7ByzgE5m2RU=", + "_parent": { + "$ref": "AAAAAAFk7ByzgE5ji+4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": 1190, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage - Transformers)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7ByzgE5nODY=", + "_parent": { + "$ref": "AAAAAAFk7ByzgE5ji+4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -816, + "top": -2442, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 1168, + "width": 217, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7ByzgE5kSiU=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7ByzgE5lggk=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7ByzgE5m2RU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7ByzgE5nODY=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7ByzgE5ogv0=", + "_parent": { + "$ref": "AAAAAAFk7ByzgE5i8C0=" + }, + "model": { + "$ref": "AAAAAAFk7BhADB1EoQk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 1208, + "width": 232.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7ByzgE5p3Ik=", + "_parent": { + "$ref": "AAAAAAFk7ByzgE5i8C0=" + }, + "model": { + "$ref": "AAAAAAFk7BhADB1EoQk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 1218, + "width": 232.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7ByzgE5qs24=", + "_parent": { + "$ref": "AAAAAAFk7ByzgE5i8C0=" + }, + "model": { + "$ref": "AAAAAAFk7BhADB1EoQk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -408, + "top": -1221, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7ByzgE5rvCs=", + "_parent": { + "$ref": "AAAAAAFk7ByzgE5i8C0=" + }, + "model": { + "$ref": "AAAAAAFk7BhADB1EoQk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -408, + "top": -1221, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 304, + "top": 1168, + "width": 217, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7ByzgE5ji+4=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7ByzgE5ogv0=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7ByzgE5p3Ik=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7ByzgE5qs24=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7ByzgE5rvCs=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7BzBU08BUlQ=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7Bhd7h3AKVk=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7BzBU08CnXw=", + "_parent": { + "$ref": "AAAAAAFk7BzBU08BUlQ=" + }, + "model": { + "$ref": "AAAAAAFk7Bhd7h3AKVk=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzBU08DJvA=", + "_parent": { + "$ref": "AAAAAAFk7BzBU08CnXw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1738, + "top": -2348, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzBU08EfNk=", + "_parent": { + "$ref": "AAAAAAFk7BzBU08CnXw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 45, + "top": 1047, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageRotationTransformer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzBU08FiBQ=", + "_parent": { + "$ref": "AAAAAAFk7BzBU08CnXw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 45, + "top": 1062, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage - Transformers)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzBU08GPmM=", + "_parent": { + "$ref": "AAAAAAFk7BzBU08CnXw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1738, + "top": -2348, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 1040, + "width": 217, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7BzBU08DJvA=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7BzBU08EfNk=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7BzBU08FiBQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7BzBU08GPmM=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7BzBVE8HPnQ=", + "_parent": { + "$ref": "AAAAAAFk7BzBU08BUlQ=" + }, + "model": { + "$ref": "AAAAAAFk7Bhd7h3AKVk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 1080, + "width": 232.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7BzBVE8I51k=", + "_parent": { + "$ref": "AAAAAAFk7BzBU08BUlQ=" + }, + "model": { + "$ref": "AAAAAAFk7Bhd7h3AKVk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 1090, + "width": 232.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7BzBVE8JaSI=", + "_parent": { + "$ref": "AAAAAAFk7BzBU08BUlQ=" + }, + "model": { + "$ref": "AAAAAAFk7Bhd7h3AKVk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -869, + "top": -1174, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7BzBVE8KhGM=", + "_parent": { + "$ref": "AAAAAAFk7BzBU08BUlQ=" + }, + "model": { + "$ref": "AAAAAAFk7Bhd7h3AKVk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -869, + "top": -1174, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 40, + "top": 1040, + "width": 217, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7BzBU08CnXw=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7BzBVE8HPnQ=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7BzBVE8I51k=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7BzBVE8JaSI=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7BzBVE8KhGM=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7BzL3k+gP3M=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7Bh7uh48Uvw=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7BzL3k+h/LE=", + "_parent": { + "$ref": "AAAAAAFk7BzL3k+gP3M=" + }, + "model": { + "$ref": "AAAAAAFk7Bh7uh48Uvw=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzL3k+i58E=", + "_parent": { + "$ref": "AAAAAAFk7BzL3k+h/LE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1562, + "top": -2188, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzL3k+jnZU=", + "_parent": { + "$ref": "AAAAAAFk7BzL3k+h/LE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 45, + "top": 1095, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageTintTransformer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzL3k+kSRM=", + "_parent": { + "$ref": "AAAAAAFk7BzL3k+h/LE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 45, + "top": 1110, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage - Transformers)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzL3k+lISM=", + "_parent": { + "$ref": "AAAAAAFk7BzL3k+h/LE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1562, + "top": -2188, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 1088, + "width": 217, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7BzL3k+i58E=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7BzL3k+jnZU=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7BzL3k+kSRM=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7BzL3k+lISM=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7BzL3k+mV6M=", + "_parent": { + "$ref": "AAAAAAFk7BzL3k+gP3M=" + }, + "model": { + "$ref": "AAAAAAFk7Bh7uh48Uvw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 1128, + "width": 232.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7BzL3k+ncwA=", + "_parent": { + "$ref": "AAAAAAFk7BzL3k+gP3M=" + }, + "model": { + "$ref": "AAAAAAFk7Bh7uh48Uvw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 1138, + "width": 232.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7BzL3k+oq28=", + "_parent": { + "$ref": "AAAAAAFk7BzL3k+gP3M=" + }, + "model": { + "$ref": "AAAAAAFk7Bh7uh48Uvw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -781, + "top": -1094, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7BzL30+p3h8=", + "_parent": { + "$ref": "AAAAAAFk7BzL3k+gP3M=" + }, + "model": { + "$ref": "AAAAAAFk7Bh7uh48Uvw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -781, + "top": -1094, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 40, + "top": 1088, + "width": 217, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7BzL3k+h/LE=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7BzL3k+mV6M=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7BzL3k+ncwA=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7BzL3k+oq28=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7BzL30+p3h8=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7BzX6lA/qV4=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7Bicxh7WCxo=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7BzX61BAfqg=", + "_parent": { + "$ref": "AAAAAAFk7BzX6lA/qV4=" + }, + "model": { + "$ref": "AAAAAAFk7Bicxh7WCxo=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzX61BBxOE=", + "_parent": { + "$ref": "AAAAAAFk7BzX61BAfqg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1284, + "top": -2076, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzX61BCI5E=", + "_parent": { + "$ref": "AAAAAAFk7BzX61BAfqg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 45, + "top": 1143, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageBlurTransformer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzX61BD59Y=", + "_parent": { + "$ref": "AAAAAAFk7BzX61BAfqg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 45, + "top": 1158, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage - Transformers)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzX61BEPAA=", + "_parent": { + "$ref": "AAAAAAFk7BzX61BAfqg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1284, + "top": -2076, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 1136, + "width": 217, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7BzX61BBxOE=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7BzX61BCI5E=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7BzX61BD59Y=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7BzX61BEPAA=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7BzX61BF/KQ=", + "_parent": { + "$ref": "AAAAAAFk7BzX6lA/qV4=" + }, + "model": { + "$ref": "AAAAAAFk7Bicxh7WCxo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 1176, + "width": 232.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7BzX61BGRt4=", + "_parent": { + "$ref": "AAAAAAFk7BzX6lA/qV4=" + }, + "model": { + "$ref": "AAAAAAFk7Bicxh7WCxo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 1186, + "width": 232.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7BzX61BHso8=", + "_parent": { + "$ref": "AAAAAAFk7BzX6lA/qV4=" + }, + "model": { + "$ref": "AAAAAAFk7Bicxh7WCxo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -642, + "top": -1038, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7BzX61BIZPE=", + "_parent": { + "$ref": "AAAAAAFk7BzX6lA/qV4=" + }, + "model": { + "$ref": "AAAAAAFk7Bicxh7WCxo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -642, + "top": -1038, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 40, + "top": 1136, + "width": 217, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7BzX61BAfqg=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7BzX61BF/KQ=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7BzX61BGRt4=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7BzX61BHso8=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7BzX61BIZPE=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7BzhyVDeD10=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7Bi24B9S1R4=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7BzhyVDf0J8=", + "_parent": { + "$ref": "AAAAAAFk7BzhyVDeD10=" + }, + "model": { + "$ref": "AAAAAAFk7Bi24B9S1R4=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzhyVDgKYc=", + "_parent": { + "$ref": "AAAAAAFk7BzhyVDf0J8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1224, + "top": -2174, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzhyVDhZ1I=", + "_parent": { + "$ref": "AAAAAAFk7BzhyVDf0J8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 45, + "top": 1191, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageFilterTransformer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzhyVDi76Y=", + "_parent": { + "$ref": "AAAAAAFk7BzhyVDf0J8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 45, + "top": 1206, + "width": 207, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage - Transformers)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7BzhyVDj9LQ=", + "_parent": { + "$ref": "AAAAAAFk7BzhyVDf0J8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1224, + "top": -2174, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 1184, + "width": 217, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7BzhyVDgKYc=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7BzhyVDhZ1I=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7BzhyVDi76Y=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7BzhyVDj9LQ=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7BzhyVDk5wU=", + "_parent": { + "$ref": "AAAAAAFk7BzhyVDeD10=" + }, + "model": { + "$ref": "AAAAAAFk7Bi24B9S1R4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 1224, + "width": 232.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7BzhyVDlMB8=", + "_parent": { + "$ref": "AAAAAAFk7BzhyVDeD10=" + }, + "model": { + "$ref": "AAAAAAFk7Bi24B9S1R4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 1234, + "width": 232.66943359375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7BzhyVDmFSk=", + "_parent": { + "$ref": "AAAAAAFk7BzhyVDeD10=" + }, + "model": { + "$ref": "AAAAAAFk7Bi24B9S1R4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -612, + "top": -1087, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7BzhyVDncPQ=", + "_parent": { + "$ref": "AAAAAAFk7BzhyVDeD10=" + }, + "model": { + "$ref": "AAAAAAFk7Bi24B9S1R4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -612, + "top": -1087, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 40, + "top": 1184, + "width": 217, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7BzhyVDf0J8=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7BzhyVDk5wU=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7BzhyVDlMB8=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7BzhyVDmFSk=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7BzhyVDncPQ=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7CKPEl9eoPA=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7CKPEV9dRro=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CKPEl9fnqg=", + "_parent": { + "$ref": "AAAAAAFk7CKPEl9eoPA=" + }, + "model": { + "$ref": "AAAAAAFk7CKPEV9dRro=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 273, + "top": 1014, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CKPEl9eoPA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CKPE19g4oc=", + "_parent": { + "$ref": "AAAAAAFk7CKPEl9eoPA=" + }, + "model": { + "$ref": "AAAAAAFk7CKPEV9dRro=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 258, + "top": 1014, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7CKPEl9eoPA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CKPE19hcmM=", + "_parent": { + "$ref": "AAAAAAFk7CKPEl9eoPA=" + }, + "model": { + "$ref": "AAAAAAFk7CKPEV9dRro=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 302, + "top": 1015, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CKPEl9eoPA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7BH3rPEP74Y=" + }, + "tail": { + "$ref": "AAAAAAFk7BxkFEpIXos=" + }, + "lineStyle": 0, + "points": "304:1043;288:1043;288:999;258:999", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7CKPEl9fnqg=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7CKPE19g4oc=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7CKPE19hcmM=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7CLPZWHJ/hM=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7CLPZWHITQ0=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CLPZWHKn64=", + "_parent": { + "$ref": "AAAAAAFk7CLPZWHJ/hM=" + }, + "model": { + "$ref": "AAAAAAFk7CLPZWHITQ0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 273, + "top": 1038, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CLPZWHJ/hM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CLPZmHLCcU=", + "_parent": { + "$ref": "AAAAAAFk7CLPZWHJ/hM=" + }, + "model": { + "$ref": "AAAAAAFk7CLPZWHITQ0=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 258, + "top": 1038, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7CLPZWHJ/hM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CLPZmHMgys=", + "_parent": { + "$ref": "AAAAAAFk7CLPZWHJ/hM=" + }, + "model": { + "$ref": "AAAAAAFk7CLPZWHITQ0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 302, + "top": 1039, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CLPZWHJ/hM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7BH3rPEP74Y=" + }, + "tail": { + "$ref": "AAAAAAFk7Bx/j0v2QMc=" + }, + "lineStyle": 0, + "points": "304:1091;288:1091;288:999;258:999", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7CLPZWHKn64=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7CLPZmHLCcU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7CLPZmHMgys=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7CMBXGQW1hM=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7CMBW2QVtcI=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CMBXGQXlOA=", + "_parent": { + "$ref": "AAAAAAFk7CMBXGQW1hM=" + }, + "model": { + "$ref": "AAAAAAFk7CMBW2QVtcI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 273, + "top": 1062, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CMBXGQW1hM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CMBXGQYxJA=", + "_parent": { + "$ref": "AAAAAAFk7CMBXGQW1hM=" + }, + "model": { + "$ref": "AAAAAAFk7CMBW2QVtcI=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 258, + "top": 1062, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7CMBXGQW1hM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CMBXGQZlBI=", + "_parent": { + "$ref": "AAAAAAFk7CMBXGQW1hM=" + }, + "model": { + "$ref": "AAAAAAFk7CMBW2QVtcI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 302, + "top": 1063, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CMBXGQW1hM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7BH3rPEP74Y=" + }, + "tail": { + "$ref": "AAAAAAFk7ByM3UyzV2E=" + }, + "lineStyle": 0, + "points": "304:1139;288:1139;288:999;258:999", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7CMBXGQXlOA=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7CMBXGQYxJA=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7CMBXGQZlBI=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7CMrm2Zj4Js=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7CMrm2ZiA3E=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CMrm2ZkGLA=", + "_parent": { + "$ref": "AAAAAAFk7CMrm2Zj4Js=" + }, + "model": { + "$ref": "AAAAAAFk7CMrm2ZiA3E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 273, + "top": 1086, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CMrm2Zj4Js=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CMrm2ZlaVA=", + "_parent": { + "$ref": "AAAAAAFk7CMrm2Zj4Js=" + }, + "model": { + "$ref": "AAAAAAFk7CMrm2ZiA3E=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 258, + "top": 1086, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7CMrm2Zj4Js=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CMrm2ZmHjI=", + "_parent": { + "$ref": "AAAAAAFk7CMrm2Zj4Js=" + }, + "model": { + "$ref": "AAAAAAFk7CMrm2ZiA3E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 302, + "top": 1087, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CMrm2Zj4Js=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7BH3rPEP74Y=" + }, + "tail": { + "$ref": "AAAAAAFk7ByzgE5i8C0=" + }, + "lineStyle": 0, + "points": "304:1187;288:1187;288:999;258:999", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7CMrm2ZkGLA=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7CMrm2ZlaVA=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7CMrm2ZmHjI=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7CNbqmh0SHk=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7CNbqmhzvEA=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CNbq2h1OVY=", + "_parent": { + "$ref": "AAAAAAFk7CNbqmh0SHk=" + }, + "model": { + "$ref": "AAAAAAFk7CNbqmhzvEA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 273, + "top": 1022, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CNbqmh0SHk=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CNbq2h2p8s=", + "_parent": { + "$ref": "AAAAAAFk7CNbqmh0SHk=" + }, + "model": { + "$ref": "AAAAAAFk7CNbqmhzvEA=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 258, + "top": 1022, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7CNbqmh0SHk=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CNbq2h38Oc=", + "_parent": { + "$ref": "AAAAAAFk7CNbqmh0SHk=" + }, + "model": { + "$ref": "AAAAAAFk7CNbqmhzvEA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 302, + "top": 1023, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CNbqmh0SHk=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7BH3rPEP74Y=" + }, + "tail": { + "$ref": "AAAAAAFk7BzBU08BUlQ=" + }, + "lineStyle": 0, + "points": "256:1059;288:1059;288:999;258:999", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7CNbq2h1OVY=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7CNbq2h2p8s=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7CNbq2h38Oc=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7CQo724O9+8=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7CQo724NRzY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CQo724PTmk=", + "_parent": { + "$ref": "AAAAAAFk7CQo724O9+8=" + }, + "model": { + "$ref": "AAAAAAFk7CQo724NRzY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 273, + "top": 1046, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CQo724O9+8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CQo724QGeo=", + "_parent": { + "$ref": "AAAAAAFk7CQo724O9+8=" + }, + "model": { + "$ref": "AAAAAAFk7CQo724NRzY=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 258, + "top": 1046, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7CQo724O9+8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CQo8G4RzYc=", + "_parent": { + "$ref": "AAAAAAFk7CQo724O9+8=" + }, + "model": { + "$ref": "AAAAAAFk7CQo724NRzY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 302, + "top": 1047, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CQo724O9+8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7BH3rPEP74Y=" + }, + "tail": { + "$ref": "AAAAAAFk7BzL3k+gP3M=" + }, + "lineStyle": 0, + "points": "256:1107;288:1107;288:999;258:999", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7CQo724PTmk=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7CQo724QGeo=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7CQo8G4RzYc=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7CRNf2/jj6Q=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7CRNf2/ipjs=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CRNf2/kF30=", + "_parent": { + "$ref": "AAAAAAFk7CRNf2/jj6Q=" + }, + "model": { + "$ref": "AAAAAAFk7CRNf2/ipjs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 273, + "top": 1070, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CRNf2/jj6Q=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CRNf2/luWo=", + "_parent": { + "$ref": "AAAAAAFk7CRNf2/jj6Q=" + }, + "model": { + "$ref": "AAAAAAFk7CRNf2/ipjs=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 258, + "top": 1070, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7CRNf2/jj6Q=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CRNf2/mrbY=", + "_parent": { + "$ref": "AAAAAAFk7CRNf2/jj6Q=" + }, + "model": { + "$ref": "AAAAAAFk7CRNf2/ipjs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 302, + "top": 1071, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CRNf2/jj6Q=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7BH3rPEP74Y=" + }, + "tail": { + "$ref": "AAAAAAFk7BzX6lA/qV4=" + }, + "lineStyle": 0, + "points": "256:1155;288:1155;288:999;258:999", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7CRNf2/kF30=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7CRNf2/luWo=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7CRNf2/mrbY=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7CRttnGaXWE=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7CRttXGZGcg=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CRttnGbT/E=", + "_parent": { + "$ref": "AAAAAAFk7CRttnGaXWE=" + }, + "model": { + "$ref": "AAAAAAFk7CRttXGZGcg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 273, + "top": 1094, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CRttnGaXWE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CRttnGcO1o=", + "_parent": { + "$ref": "AAAAAAFk7CRttnGaXWE=" + }, + "model": { + "$ref": "AAAAAAFk7CRttXGZGcg=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 258, + "top": 1094, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7CRttnGaXWE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CRttnGdiWQ=", + "_parent": { + "$ref": "AAAAAAFk7CRttnGaXWE=" + }, + "model": { + "$ref": "AAAAAAFk7CRttXGZGcg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 303, + "top": 1095, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CRttnGaXWE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7BH3rPEP74Y=" + }, + "tail": { + "$ref": "AAAAAAFk7BzhyVDeD10=" + }, + "lineStyle": 0, + "points": "256:1203;288:1203;288:999;258:999", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7CRttnGbT/E=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7CRttnGcO1o=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7CRttnGdiWQ=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7CarUIbnZao=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7CZN3IZtF9w=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7CarUIbozAk=", + "_parent": { + "$ref": "AAAAAAFk7CarUIbnZao=" + }, + "model": { + "$ref": "AAAAAAFk7CZN3IZtF9w=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7CarUIbp6sE=", + "_parent": { + "$ref": "AAAAAAFk7CarUIbozAk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -92, + "top": -62, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7CarUIbqswQ=", + "_parent": { + "$ref": "AAAAAAFk7CarUIbozAk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 189, + "top": 23, + "width": 222, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDAnimatedImageView (WebCache)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7CarUIbrMfg=", + "_parent": { + "$ref": "AAAAAAFk7CarUIbozAk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 189, + "top": 38, + "width": 222, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7CarUIbs6OI=", + "_parent": { + "$ref": "AAAAAAFk7CarUIbozAk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -92, + "top": -62, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 184, + "top": 16, + "width": 232, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7CarUIbp6sE=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7CarUIbqswQ=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7CarUIbrMfg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7CarUIbs6OI=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7CarUIbt+ZA=", + "_parent": { + "$ref": "AAAAAAFk7CarUIbnZao=" + }, + "model": { + "$ref": "AAAAAAFk7CZN3IZtF9w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 184, + "top": 56, + "width": 247.583984375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7CarUIbuwH4=", + "_parent": { + "$ref": "AAAAAAFk7CarUIbnZao=" + }, + "model": { + "$ref": "AAAAAAFk7CZN3IZtF9w=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7CbO9Yi1Aew=", + "_parent": { + "$ref": "AAAAAAFk7CarUIbuwH4=" + }, + "model": { + "$ref": "AAAAAAFk7CbOtYiUask=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 189, + "top": 71, + "width": 237.583984375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sd_setImageWithURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 184, + "top": 66, + "width": 247.583984375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7CarUYbvJ1M=", + "_parent": { + "$ref": "AAAAAAFk7CarUIbnZao=" + }, + "model": { + "$ref": "AAAAAAFk7CZN3IZtF9w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -46, + "top": -31, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7CarUYbwIR8=", + "_parent": { + "$ref": "AAAAAAFk7CarUIbnZao=" + }, + "model": { + "$ref": "AAAAAAFk7CZN3IZtF9w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -46, + "top": -31, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 184, + "top": 16, + "width": 232, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7CarUIbozAk=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7CarUIbt+ZA=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7CarUIbuwH4=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7CarUYbvJ1M=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7CarUYbwIR8=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk7CeGF4sV54E=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7CeGFosTNLw=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CeGF4sWkhg=", + "_parent": { + "$ref": "AAAAAAFk7CeGF4sV54E=" + }, + "model": { + "$ref": "AAAAAAFk7CeGFosTNLw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 299, + "top": 102, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CeGF4sV54E=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CeGF4sXQ6Q=", + "_parent": { + "$ref": "AAAAAAFk7CeGF4sV54E=" + }, + "model": { + "$ref": "AAAAAAFk7CeGFosTNLw=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 299, + "top": 87, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7CeGF4sV54E=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7CeGF4sYReA=", + "_parent": { + "$ref": "AAAAAAFk7CeGF4sV54E=" + }, + "model": { + "$ref": "AAAAAAFk7CeGFosTNLw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 299, + "top": 132, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7CeGF4sV54E=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFXmsqnFRq0kTA=" + }, + "tail": { + "$ref": "AAAAAAFk7CarUIbnZao=" + }, + "lineStyle": 0, + "points": "299:55;299:123;360:123", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7CeGF4sWkhg=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7CeGF4sXQ6Q=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7CeGF4sYReA=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk7Cknl6IcBF4=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7Cj0NKGudXg=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7Cknl6Id/H0=", + "_parent": { + "$ref": "AAAAAAFk7Cknl6IcBF4=" + }, + "model": { + "$ref": "AAAAAAFk7Cj0NKGudXg=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7Cknl6IeV5Q=", + "_parent": { + "$ref": "AAAAAAFk7Cknl6Id/H0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1117, + "top": 1013, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7Cknl6IfgXo=", + "_parent": { + "$ref": "AAAAAAFk7Cknl6Id/H0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1117, + "top": 1028, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDAnimatedImage", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7Cknl6Ig/aU=", + "_parent": { + "$ref": "AAAAAAFk7Cknl6Id/H0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1117, + "top": 1043, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7Cknl6IhAp4=", + "_parent": { + "$ref": "AAAAAAFk7Cknl6Id/H0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -62, + "top": -1980, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1112, + "top": 1008, + "width": 138, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7Cknl6IeV5Q=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7Cknl6IfgXo=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7Cknl6Ig/aU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7Cknl6IhAp4=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7CknmKIiFpc=", + "_parent": { + "$ref": "AAAAAAFk7Cknl6IcBF4=" + }, + "model": { + "$ref": "AAAAAAFk7Cj0NKGudXg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -31, + "top": -990, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7CknmKIjcPI=", + "_parent": { + "$ref": "AAAAAAFk7Cknl6IcBF4=" + }, + "model": { + "$ref": "AAAAAAFk7Cj0NKGudXg=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7Cm8e6ZX9WA=", + "_parent": { + "$ref": "AAAAAAFk7CknmKIjcPI=" + }, + "model": { + "$ref": "AAAAAAFk7Cm8PqY2Qm8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1117, + "top": 82, + "width": 170.5361328125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(animatedCoder, scale)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7CoRK6lU2ew=", + "_parent": { + "$ref": "AAAAAAFk7CknmKIjcPI=" + }, + "model": { + "$ref": "AAAAAAFk7CoQ7KkzMJ4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1117, + "top": 97, + "width": 170.5361328125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+preloadAllFrames()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7CovyqrDhdo=", + "_parent": { + "$ref": "AAAAAAFk7CknmKIjcPI=" + }, + "model": { + "$ref": "AAAAAAFk7CovjqqiyHk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1117, + "top": 112, + "width": 170.5361328125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+unloadAllFrames()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7CpK26wyaL8=", + "_parent": { + "$ref": "AAAAAAFk7CknmKIjcPI=" + }, + "model": { + "$ref": "AAAAAAFk7CpKoKwRISY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1117, + "top": 127, + "width": 170.5361328125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+isAllFramesLoaded(): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1112, + "top": 1061, + "width": 180.5361328125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7CknmKIk7/4=", + "_parent": { + "$ref": "AAAAAAFk7Cknl6IcBF4=" + }, + "model": { + "$ref": "AAAAAAFk7Cj0NKGudXg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -31, + "top": -990, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7CknmKIlgLs=", + "_parent": { + "$ref": "AAAAAAFk7Cknl6IcBF4=" + }, + "model": { + "$ref": "AAAAAAFk7Cj0NKGudXg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -31, + "top": -990, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1112, + "top": 1008, + "width": 162, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7Cknl6Id/H0=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7CknmKIiFpc=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7CknmKIjcPI=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7CknmKIk7/4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7CknmKIlgLs=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAFk7ClkOKPrtBQ=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7ClkOKPpj1g=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7ClkOaPs//c=", + "_parent": { + "$ref": "AAAAAAFk7ClkOKPrtBQ=" + }, + "model": { + "$ref": "AAAAAAFk7ClkOKPpj1g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1201, + "top": 951, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7ClkOKPrtBQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7ClkOaPtr8w=", + "_parent": { + "$ref": "AAAAAAFk7ClkOKPrtBQ=" + }, + "model": { + "$ref": "AAAAAAFk7ClkOKPpj1g=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1186, + "top": 951, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7ClkOKPrtBQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7ClkOaPud6o=", + "_parent": { + "$ref": "AAAAAAFk7ClkOKPrtBQ=" + }, + "model": { + "$ref": "AAAAAAFk7ClkOKPpj1g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1230, + "top": 952, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7ClkOKPrtBQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFky0TjgJYYOQE=" + }, + "tail": { + "$ref": "AAAAAAFk7Cknl6IcBF4=" + }, + "lineStyle": 0, + "points": "1216:1008;1216:908", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7ClkOaPs//c=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7ClkOaPtr8w=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7ClkOaPud6o=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7DA7OzoeKZo=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7DA7OzofsEI=", + "_parent": { + "$ref": "AAAAAAFk7DA7OzoeKZo=" + }, + "model": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7DA7PDogIps=", + "_parent": { + "$ref": "AAAAAAFk7DA7OzofsEI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -42, + "top": -2184, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DA7PDohSuA=", + "_parent": { + "$ref": "AAAAAAFk7DA7OzofsEI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1197, + "top": 1111, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDAnimatedImage", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DA7PDoiiIY=", + "_parent": { + "$ref": "AAAAAAFk7DA7OzofsEI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1197, + "top": 1126, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DA7PDoj+aY=", + "_parent": { + "$ref": "AAAAAAFk7DA7OzofsEI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -42, + "top": -2184, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1192, + "top": 1104, + "width": 128, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7DA7PDogIps=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7DA7PDohSuA=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7DA7PDoiiIY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7DA7PDoj+aY=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7DA7PDokx/Y=", + "_parent": { + "$ref": "AAAAAAFk7DA7OzoeKZo=" + }, + "model": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DOHD1cF2w8=", + "_parent": { + "$ref": "AAAAAAFk7DA7PDokx/Y=" + }, + "model": { + "$ref": "AAAAAAFk7DOG2FbkH2w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1261, + "top": 101, + "width": 255.06787109375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animatedImageFormat: SDImageFormat", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DO4U1h008k=", + "_parent": { + "$ref": "AAAAAAFk7DA7PDokx/Y=" + }, + "model": { + "$ref": "AAAAAAFk7DO4G1hTjI0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1261, + "top": 116, + "width": 255.06787109375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animatedImageData: Data", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DQVNlsv1k8=", + "_parent": { + "$ref": "AAAAAAFk7DA7PDokx/Y=" + }, + "model": { + "$ref": "AAAAAAFk7DQVAVsOZyY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1261, + "top": 131, + "width": 255.06787109375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+scale: Float", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1192, + "top": 1144, + "width": 265.06787109375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7DA7PDolQ9E=", + "_parent": { + "$ref": "AAAAAAFk7DA7OzoeKZo=" + }, + "model": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7DH2wUmkmLY=", + "_parent": { + "$ref": "AAAAAAFk7DA7PDolQ9E=" + }, + "model": { + "$ref": "AAAAAAFk7DH2i0mDavU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1261, + "top": 154, + "width": 255.06787109375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(name, bundle, traitCollection)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7DKNLE7FkwE=", + "_parent": { + "$ref": "AAAAAAFk7DA7PDolQ9E=" + }, + "model": { + "$ref": "AAAAAAFk7DKM7E6kOa0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1261, + "top": 169, + "width": 255.06787109375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(path)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7DK+91DO7A4=", + "_parent": { + "$ref": "AAAAAAFk7DA7PDolQ9E=" + }, + "model": { + "$ref": "AAAAAAFk7DK+w1CtoF8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1261, + "top": 184, + "width": 255.06787109375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(data, scale)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7DMSQlQIbYA=", + "_parent": { + "$ref": "AAAAAAFk7DA7PDolQ9E=" + }, + "model": { + "$ref": "AAAAAAFk7DMSCVPnFmw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1261, + "top": 199, + "width": 255.06787109375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(animatedCoder, scale)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1192, + "top": 1197, + "width": 265.06787109375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7DA7PTom4PI=", + "_parent": { + "$ref": "AAAAAAFk7DA7OzoeKZo=" + }, + "model": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -21, + "top": -1092, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7DA7PTonbJo=", + "_parent": { + "$ref": "AAAAAAFk7DA7OzoeKZo=" + }, + "model": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -21, + "top": -1092, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1192, + "top": 1104, + "width": 128, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7DA7OzofsEI=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7DA7PDokx/Y=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7DA7PDolQ9E=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7DA7PTom4PI=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7DA7PTonbJo=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7DBYBDxEEpo=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7DBYBDxD/3s=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DBYBTxFCZY=", + "_parent": { + "$ref": "AAAAAAFk7DBYBDxEEpo=" + }, + "model": { + "$ref": "AAAAAAFk7DBYBDxD/3s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1201, + "top": 1075, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7DBYBDxEEpo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DBYBTxGQQY=", + "_parent": { + "$ref": "AAAAAAFk7DBYBDxEEpo=" + }, + "model": { + "$ref": "AAAAAAFk7DBYBDxD/3s=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1186, + "top": 1075, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7DBYBDxEEpo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DBYBTxHT/I=", + "_parent": { + "$ref": "AAAAAAFk7DBYBDxEEpo=" + }, + "model": { + "$ref": "AAAAAAFk7DBYBDxD/3s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1230, + "top": 1076, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7DBYBDxEEpo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7Cknl6IcBF4=" + }, + "tail": { + "$ref": "AAAAAAFk7DA7OzoeKZo=" + }, + "lineStyle": 0, + "points": "1216:1104;1216:1060", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7DBYBTxFCZY=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7DBYBTxGQQY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7DBYBTxHT/I=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7DEr1ULU+E4=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7DEaV0J1rfc=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7DEr1ULVwi0=", + "_parent": { + "$ref": "AAAAAAFk7DEr1ULU+E4=" + }, + "model": { + "$ref": "AAAAAAFk7DEaV0J1rfc=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7DEr1ULWU0g=", + "_parent": { + "$ref": "AAAAAAFk7DEr1ULVwi0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -250, + "top": -2326, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DEr1ULXvGw=", + "_parent": { + "$ref": "AAAAAAFk7DEr1ULVwi0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1285, + "top": 1015, + "width": 67, + "height": 13, + "autoResize": false, + "underline": false, + "text": "UIImage", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DEr1ULYcCQ=", + "_parent": { + "$ref": "AAAAAAFk7DEr1ULVwi0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1285, + "top": 1030, + "width": 67, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from UIKit)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DEr1ULZri0=", + "_parent": { + "$ref": "AAAAAAFk7DEr1ULVwi0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -250, + "top": -2326, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1280, + "top": 1008, + "width": 77, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7DEr1ULWU0g=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7DEr1ULXvGw=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7DEr1ULYcCQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7DEr1ULZri0=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7DEr1kLamVE=", + "_parent": { + "$ref": "AAAAAAFk7DEr1ULU+E4=" + }, + "model": { + "$ref": "AAAAAAFk7DEaV0J1rfc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1280, + "top": 1048, + "width": 81.98876953125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7DEr1kLbv0E=", + "_parent": { + "$ref": "AAAAAAFk7DEr1ULU+E4=" + }, + "model": { + "$ref": "AAAAAAFk7DEaV0J1rfc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1280, + "top": 1058, + "width": 81.98876953125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7DEr1kLcqWA=", + "_parent": { + "$ref": "AAAAAAFk7DEr1ULU+E4=" + }, + "model": { + "$ref": "AAAAAAFk7DEaV0J1rfc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -125, + "top": -1163, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7DEr1kLdArM=", + "_parent": { + "$ref": "AAAAAAFk7DEr1ULU+E4=" + }, + "model": { + "$ref": "AAAAAAFk7DEaV0J1rfc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -125, + "top": -1163, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1280, + "top": 1008, + "width": 77, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7DEr1ULVwi0=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7DEr1kLamVE=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7DEr1kLbv0E=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7DEr1kLcqWA=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7DEr1kLdArM=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAFk7DFeU0Rl3h4=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7DFeUkRjApo=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DFeU0Rms0Y=", + "_parent": { + "$ref": "AAAAAAFk7DFeU0Rl3h4=" + }, + "model": { + "$ref": "AAAAAAFk7DFeUkRjApo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1289, + "top": 1068, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7DFeU0Rl3h4=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DFeU0RnlXQ=", + "_parent": { + "$ref": "AAAAAAFk7DFeU0Rl3h4=" + }, + "model": { + "$ref": "AAAAAAFk7DFeUkRjApo=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1274, + "top": 1068, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7DFeU0Rl3h4=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DFeU0Ro/vA=", + "_parent": { + "$ref": "AAAAAAFk7DFeU0Rl3h4=" + }, + "model": { + "$ref": "AAAAAAFk7DFeUkRjApo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1318, + "top": 1069, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7DFeU0Rl3h4=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7DEr1ULU+E4=" + }, + "tail": { + "$ref": "AAAAAAFk7DA7OzoeKZo=" + }, + "lineStyle": 0, + "points": "1304:1104;1304:1047", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7DFeU0Rms0Y=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7DFeU0RnlXQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7DFeU0Ro/vA=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7DXWVGM6x9A=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7DWl62Lbshc=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7DXWVWM7lA0=", + "_parent": { + "$ref": "AAAAAAFk7DXWVGM6x9A=" + }, + "model": { + "$ref": "AAAAAAFk7DWl62Lbshc=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7DXWVWM866M=", + "_parent": { + "$ref": "AAAAAAFk7DXWVWM7lA0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -344, + "top": -2600, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DXWVWM9pwo=", + "_parent": { + "$ref": "AAAAAAFk7DXWVWM7lA0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 861, + "top": 1111, + "width": 81, + "height": 13, + "autoResize": false, + "underline": false, + "text": "UIImageView", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DXWVWM+Un0=", + "_parent": { + "$ref": "AAAAAAFk7DXWVWM7lA0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 861, + "top": 1126, + "width": 81, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from UIKit)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DXWVWM/GvA=", + "_parent": { + "$ref": "AAAAAAFk7DXWVWM7lA0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -344, + "top": -2600, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 856, + "top": 1104, + "width": 91, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7DXWVWM866M=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7DXWVWM9pwo=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7DXWVWM+Un0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7DXWVWM/GvA=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7DXWVWNA2/A=", + "_parent": { + "$ref": "AAAAAAFk7DXWVGM6x9A=" + }, + "model": { + "$ref": "AAAAAAFk7DWl62Lbshc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 856, + "top": 1144, + "width": 96.77880859375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7DXWVmNB7XI=", + "_parent": { + "$ref": "AAAAAAFk7DXWVGM6x9A=" + }, + "model": { + "$ref": "AAAAAAFk7DWl62Lbshc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 856, + "top": 1154, + "width": 96.77880859375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7DXWVmNC04Q=", + "_parent": { + "$ref": "AAAAAAFk7DXWVGM6x9A=" + }, + "model": { + "$ref": "AAAAAAFk7DWl62Lbshc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -172, + "top": -1300, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7DXWVmNDAzg=", + "_parent": { + "$ref": "AAAAAAFk7DXWVGM6x9A=" + }, + "model": { + "$ref": "AAAAAAFk7DWl62Lbshc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -172, + "top": -1300, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 856, + "top": 1104, + "width": 91, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7DXWVWM7lA0=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7DXWVWNA2/A=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7DXWVmNB7XI=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7DXWVmNC04Q=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7DXWVmNDAzg=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7DXlLWPZ6qk=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7DXlLWPaDAA=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPZ6qk=" + }, + "model": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7DXlLWPbzW4=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPaDAA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -498, + "top": -2690, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DXlLWPcXAY=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPaDAA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 997, + "top": 1111, + "width": 145, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDAnimatedImageView", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DXlLWPdwY0=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPaDAA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 997, + "top": 1126, + "width": 145, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DXlLWPeixU=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPaDAA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -498, + "top": -2690, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 992, + "top": 1104, + "width": 155, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7DXlLWPbzW4=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7DXlLWPcXAY=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7DXlLWPdwY0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7DXlLWPeixU=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7DXlLWPfu+w=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPZ6qk=" + }, + "model": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DaZ4G2YyVM=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPfu+w=" + }, + "model": { + "$ref": "AAAAAAFk7DaZpG13UcQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1077, + "top": 93, + "width": 167.55908203125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+currentFrame", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DbHHW+A+Jo=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPfu+w=" + }, + "model": { + "$ref": "AAAAAAFk7DbG6G9fPWY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1077, + "top": 108, + "width": 167.55908203125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+currentFrameIndex", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DbkhHDvA+o=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPfu+w=" + }, + "model": { + "$ref": "AAAAAAFk7DbkTXDOHZI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1077, + "top": 123, + "width": 167.55908203125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+currentLoopCount", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DcDz3JegjI=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPfu+w=" + }, + "model": { + "$ref": "AAAAAAFk7DcDmHI9EDE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1077, + "top": 138, + "width": 167.55908203125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+shouldCustomLoopCount", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7Dc183SgtAI=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPfu+w=" + }, + "model": { + "$ref": "AAAAAAFk7Dc1vHR/unM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1077, + "top": 153, + "width": 167.55908203125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animationRepeatCount", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DdOyXYPyfk=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPfu+w=" + }, + "model": { + "$ref": "AAAAAAFk7DdOkHXuWe8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1077, + "top": 168, + "width": 167.55908203125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+maxBufferSize", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7Ddph3d+jug=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPfu+w=" + }, + "model": { + "$ref": "AAAAAAFk7DdpU3dd33Y=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1077, + "top": 183, + "width": 167.55908203125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+shouldIncrementalLoad", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DeDAnjt9J4=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPfu+w=" + }, + "model": { + "$ref": "AAAAAAFk7DeCxXjMVds=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1077, + "top": 198, + "width": 167.55908203125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+runLoopMode", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 992, + "top": 1144, + "width": 177.55908203125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7DXlLWPgzzM=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPZ6qk=" + }, + "model": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 992, + "top": 1272, + "width": 177.55908203125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7DXlLWPh27g=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPZ6qk=" + }, + "model": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -249, + "top": -1345, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7DXlLWPign0=", + "_parent": { + "$ref": "AAAAAAFk7DXlLWPZ6qk=" + }, + "model": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -249, + "top": -1345, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 992, + "top": 1104, + "width": 155, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7DXlLWPaDAA=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7DXlLWPfu+w=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7DXlLWPgzzM=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7DXlLWPh27g=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7DXlLWPign0=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAFk7DZYV2rRI6A=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7DZYV2rPuLs=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DZYWGrSICw=", + "_parent": { + "$ref": "AAAAAAFk7DZYV2rRI6A=" + }, + "model": { + "$ref": "AAAAAAFk7DZYV2rPuLs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 968, + "top": 1132, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7DZYV2rRI6A=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DZYWGrTbps=", + "_parent": { + "$ref": "AAAAAAFk7DZYV2rRI6A=" + }, + "model": { + "$ref": "AAAAAAFk7DZYV2rPuLs=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 968, + "top": 1147, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7DZYV2rRI6A=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DZYWGrU7rM=", + "_parent": { + "$ref": "AAAAAAFk7DZYV2rRI6A=" + }, + "model": { + "$ref": "AAAAAAFk7DZYV2rPuLs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 969, + "top": 1102, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7DZYV2rRI6A=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7DXWVGM6x9A=" + }, + "tail": { + "$ref": "AAAAAAFk7DXlLWPZ6qk=" + }, + "lineStyle": 0, + "points": "992:1123;946:1123", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7DZYWGrSICw=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7DZYWGrTbps=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7DZYWGrU7rM=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7DkhdHrCH1M=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7DkhdXrDFAo=", + "_parent": { + "$ref": "AAAAAAFk7DkhdHrCH1M=" + }, + "model": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7DkhdXrEZoY=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrDFAo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1568, + "top": -3398, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DkhdXrFCFw=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrDFAo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 775, + "width": 146, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageTransition", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DkhdXrGy3I=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrDFAo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 790, + "width": 146, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7DkhdXrHtoY=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrDFAo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1568, + "top": -3398, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 768, + "width": 156, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7DkhdXrEZoY=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7DkhdXrFCFw=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7DkhdXrGy3I=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7DkhdXrHtoY=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7DkhdXrIi38=", + "_parent": { + "$ref": "AAAAAAFk7DkhdHrCH1M=" + }, + "model": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DkhonsG1Mw=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrIi38=" + }, + "model": { + "$ref": "AAAAAAFk7DkRAnpj0zo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -571, + "top": -659, + "width": 155.44140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+avoidAutoSetImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7Dk9w3vew3w=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrIi38=" + }, + "model": { + "$ref": "AAAAAAFk7Dk9kHu9TbQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -571, + "top": -644, + "width": 155.44140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+duration", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DlVvn1NumQ=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrIi38=" + }, + "model": { + "$ref": "AAAAAAFk7DlVhH0silI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -571, + "top": -629, + "width": 155.44140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animationOptions", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DlyWn68nCE=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrIi38=" + }, + "model": { + "$ref": "AAAAAAFk7DlyIH6bXfc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -571, + "top": -614, + "width": 155.44140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+prepares", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DmRDoArDII=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrIi38=" + }, + "model": { + "$ref": "AAAAAAFk7DmQ2IAKsT8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -571, + "top": -599, + "width": 155.44140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animations", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DmwXIGa8Yw=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrIi38=" + }, + "model": { + "$ref": "AAAAAAFk7DmwIoF5RvY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -571, + "top": -584, + "width": 155.44140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+completion", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DoQt4MJ9YA=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrIi38=" + }, + "model": { + "$ref": "AAAAAAFk7DoQgYLooEE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -571, + "top": -569, + "width": 155.44140625, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+fade", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7Doy84Tx6y8=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrIi38=" + }, + "model": { + "$ref": "AAAAAAFk7DoyvITQMB4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -571, + "top": -554, + "width": 155.44140625, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+flipFromLeft", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DpQl4bZ0T8=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrIi38=" + }, + "model": { + "$ref": "AAAAAAFk7DpQW4a4gGQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -571, + "top": -539, + "width": 155.44140625, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+flipFromRight", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DqAvIjBRUM=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrIi38=" + }, + "model": { + "$ref": "AAAAAAFk7DqAhYigq5c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -571, + "top": -524, + "width": 155.44140625, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+flipFromTop", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DqhkYqpsrQ=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrIi38=" + }, + "model": { + "$ref": "AAAAAAFk7DqhWYqIfdY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -571, + "top": -509, + "width": 155.44140625, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+flipFromBottom", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DrIpIyRypU=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrIi38=" + }, + "model": { + "$ref": "AAAAAAFk7DrIaoxwRsk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -571, + "top": -494, + "width": 155.44140625, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+curlUp", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7DrrOI559XM=", + "_parent": { + "$ref": "AAAAAAFk7DkhdXrIi38=" + }, + "model": { + "$ref": "AAAAAAFk7Drq/45YO1k=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -571, + "top": -479, + "width": 155.44140625, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+curlDown", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 808, + "width": 165.44140625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7DkhdnrJRwM=", + "_parent": { + "$ref": "AAAAAAFk7DkhdHrCH1M=" + }, + "model": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 1011, + "width": 165.44140625, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7DkhdnrK5Ag=", + "_parent": { + "$ref": "AAAAAAFk7DkhdHrCH1M=" + }, + "model": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -784, + "top": -1699, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7DkhdnrLstQ=", + "_parent": { + "$ref": "AAAAAAFk7DkhdHrCH1M=" + }, + "model": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -784, + "top": -1699, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 768, + "width": 156, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7DkhdXrDFAo=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7DkhdXrIi38=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7DkhdnrJRwM=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7DkhdnrK5Ag=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7DkhdnrLstQ=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk7DwdIZcS4Ac=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7DwdIJcO1bc=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DwdIpcT85I=", + "_parent": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "model": { + "$ref": "AAAAAAFk7DwdIJcO1bc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1168, + "top": 1129, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DwdIpcUBsg=", + "_parent": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "model": { + "$ref": "AAAAAAFk7DwdIJcO1bc=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1168, + "top": 1144, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DwdIpcVTbI=", + "_parent": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "model": { + "$ref": "AAAAAAFk7DwdIJcO1bc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1169, + "top": 1099, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DwdIpcW0FY=", + "_parent": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "model": { + "$ref": "AAAAAAFk7DwdIJcP5mg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1166, + "top": 1128, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DwdIpcX4D8=", + "_parent": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "model": { + "$ref": "AAAAAAFk7DwdIJcP5mg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1163, + "top": 1142, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DwdIpcYqvU=", + "_parent": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "model": { + "$ref": "AAAAAAFk7DwdIJcP5mg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1170, + "top": 1101, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DwdIpcZ+Fs=", + "_parent": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "model": { + "$ref": "AAAAAAFk7DwdIZcQYP4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1171, + "top": 1128, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DwdIpcahyU=", + "_parent": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "model": { + "$ref": "AAAAAAFk7DwdIZcQYP4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1174, + "top": 1142, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7DwdIpcbvUQ=", + "_parent": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "model": { + "$ref": "AAAAAAFk7DwdIZcQYP4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1167, + "top": 1101, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk7DwdI5ccuHI=", + "_parent": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "model": { + "$ref": "AAAAAAFk7DwdIJcP5mg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -24, + "top": -899, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk7DwdI5cdtfc=", + "_parent": { + "$ref": "AAAAAAFk7DwdIZcS4Ac=" + }, + "model": { + "$ref": "AAAAAAFk7DwdIZcQYP4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -24, + "top": -899, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7DXlLWPZ6qk=" + }, + "tail": { + "$ref": "AAAAAAFk7DA7OzoeKZo=" + }, + "lineStyle": 0, + "points": "1192:1120;1146:1120", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7DwdIpcT85I=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7DwdIpcUBsg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7DwdIpcVTbI=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk7DwdIpcW0FY=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk7DwdIpcX4D8=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk7DwdIpcYqvU=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk7DwdIpcZ+Fs=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk7DwdIpcahyU=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk7DwdIpcbvUQ=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk7DwdI5ccuHI=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk7DwdI5cdtfc=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk7D1LoKHDmQU=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7D0m86FYiZQ=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7D1LoaHEanQ=", + "_parent": { + "$ref": "AAAAAAFk7D1LoKHDmQU=" + }, + "model": { + "$ref": "AAAAAAFk7D0m86FYiZQ=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7D1LoaHFrJ4=", + "_parent": { + "$ref": "AAAAAAFk7D1LoaHEanQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 549, + "top": 1061, + "width": 148, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7D1LoaHGV4w=", + "_parent": { + "$ref": "AAAAAAFk7D1LoaHEanQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 549, + "top": 1076, + "width": 148, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageIndicator", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7D1LoaHHMC0=", + "_parent": { + "$ref": "AAAAAAFk7D1LoaHEanQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 549, + "top": 1091, + "width": 148, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7D1LoaHI1HY=", + "_parent": { + "$ref": "AAAAAAFk7D1LoaHEanQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1510, + "top": -2684, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 544, + "top": 1056, + "width": 158, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7D1LoaHFrJ4=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7D1LoaHGV4w=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7D1LoaHHMC0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7D1LoaHI1HY=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7D1LoaHJSCQ=", + "_parent": { + "$ref": "AAAAAAFk7D1LoKHDmQU=" + }, + "model": { + "$ref": "AAAAAAFk7D0m86FYiZQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -755, + "top": -1342, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7D1LoaHKjOE=", + "_parent": { + "$ref": "AAAAAAFk7D1LoKHDmQU=" + }, + "model": { + "$ref": "AAAAAAFk7D0m86FYiZQ=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7D1tdaN47NY=", + "_parent": { + "$ref": "AAAAAAFk7D1LoaHKjOE=" + }, + "model": { + "$ref": "AAAAAAFk7D1tOKNUQpw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 181, + "top": -198, + "width": 180.19921875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+indicatorView()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7D2NWKULlT4=", + "_parent": { + "$ref": "AAAAAAFk7D1LoaHKjOE=" + }, + "model": { + "$ref": "AAAAAAFk7D2NH6TnfK0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 181, + "top": -183, + "width": 180.19921875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+startAnimatingIndicator()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7D2jyqaez8Q=", + "_parent": { + "$ref": "AAAAAAFk7D1LoaHKjOE=" + }, + "model": { + "$ref": "AAAAAAFk7D2jk6Z6puU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 181, + "top": -168, + "width": 180.19921875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+stopAnimatingIndicator()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk7D25sqgxtQ8=", + "_parent": { + "$ref": "AAAAAAFk7D1LoaHKjOE=" + }, + "model": { + "$ref": "AAAAAAFk7D25d6gNaKY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 181, + "top": -153, + "width": 180.19921875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+updateProgress()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 544, + "top": 1109, + "width": 190.19921875, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7D1LoqHL3F4=", + "_parent": { + "$ref": "AAAAAAFk7D1LoKHDmQU=" + }, + "model": { + "$ref": "AAAAAAFk7D0m86FYiZQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -755, + "top": -1342, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7D1LoqHMuOU=", + "_parent": { + "$ref": "AAAAAAFk7D1LoKHDmQU=" + }, + "model": { + "$ref": "AAAAAAFk7D0m86FYiZQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -755, + "top": -1342, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 544, + "top": 1056, + "width": 182, + "height": 53, + "autoResize": true, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7D1LoaHEanQ=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7D1LoaHJSCQ=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7D1LoaHKjOE=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7D1LoqHL3F4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7D1LoqHMuOU=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7D6tiK11uE8=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7D56nKz+DL8=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7D6tiK122Zs=", + "_parent": { + "$ref": "AAAAAAFk7D6tiK11uE8=" + }, + "model": { + "$ref": "AAAAAAFk7D56nKz+DL8=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7D6tia13pB4=", + "_parent": { + "$ref": "AAAAAAFk7D6tiK122Zs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -664, + "top": -2454, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7D6tia14vgo=", + "_parent": { + "$ref": "AAAAAAFk7D6tiK122Zs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 749, + "top": 1175, + "width": 184, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageActivityIndicator", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7D6tia159Yw=", + "_parent": { + "$ref": "AAAAAAFk7D6tiK122Zs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 749, + "top": 1190, + "width": 184, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7D6tia16Ewg=", + "_parent": { + "$ref": "AAAAAAFk7D6tiK122Zs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -664, + "top": -2454, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 744, + "top": 1168, + "width": 194, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7D6tia13pB4=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7D6tia14vgo=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7D6tia159Yw=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7D6tia16Ewg=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7D6tia17sn8=", + "_parent": { + "$ref": "AAAAAAFk7D6tiK11uE8=" + }, + "model": { + "$ref": "AAAAAAFk7D56nKz+DL8=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7D9GfbK7Wv0=", + "_parent": { + "$ref": "AAAAAAFk7D6tia17sn8=" + }, + "model": { + "$ref": "AAAAAAFk7D9GQLKXmoI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 365, + "top": 61, + "width": 196.97412109375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+gray", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7D9mp7TTxmg=", + "_parent": { + "$ref": "AAAAAAFk7D6tia17sn8=" + }, + "model": { + "$ref": "AAAAAAFk7D9ma7Sv4PA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 365, + "top": 76, + "width": 196.97412109375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+grayLarge", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7D+FIrbrZEQ=", + "_parent": { + "$ref": "AAAAAAFk7D6tia17sn8=" + }, + "model": { + "$ref": "AAAAAAFk7D+E67bH8oY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 365, + "top": 91, + "width": 196.97412109375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+white", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7D+YaLkDLZU=", + "_parent": { + "$ref": "AAAAAAFk7D6tia17sn8=" + }, + "model": { + "$ref": "AAAAAAFk7D+YK7jfdL0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 365, + "top": 106, + "width": 196.97412109375, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+whiteLarge", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 744, + "top": 1208, + "width": 206.97412109375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7D6tiq184G0=", + "_parent": { + "$ref": "AAAAAAFk7D6tiK11uE8=" + }, + "model": { + "$ref": "AAAAAAFk7D56nKz+DL8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 744, + "top": 1276, + "width": 206.97412109375, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7D6tiq19dhE=", + "_parent": { + "$ref": "AAAAAAFk7D6tiK11uE8=" + }, + "model": { + "$ref": "AAAAAAFk7D56nKz+DL8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -332, + "top": -1227, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7D6ti61+sgQ=", + "_parent": { + "$ref": "AAAAAAFk7D6tiK11uE8=" + }, + "model": { + "$ref": "AAAAAAFk7D56nKz+DL8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -332, + "top": -1227, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 744, + "top": 1168, + "width": 194, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7D6tiK122Zs=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7D6tia17sn8=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7D6tiq184G0=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7D6tiq19dhE=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7D6ti61+sgQ=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7D7FLq9L+0I=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7D7FLq9KEOE=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7D7FLq9MhrY=", + "_parent": { + "$ref": "AAAAAAFk7D7FLq9L+0I=" + }, + "model": { + "$ref": "AAAAAAFk7D7FLq9KEOE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 736, + "top": 1161, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7D7FLq9L+0I=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7D7FL69NywQ=", + "_parent": { + "$ref": "AAAAAAFk7D7FLq9L+0I=" + }, + "model": { + "$ref": "AAAAAAFk7D7FLq9KEOE=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 736, + "top": 1176, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7D7FLq9L+0I=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7D7FL69OLhM=", + "_parent": { + "$ref": "AAAAAAFk7D7FLq9L+0I=" + }, + "model": { + "$ref": "AAAAAAFk7D7FLq9KEOE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 737, + "top": 1131, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7D7FLq9L+0I=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7D1LoKHDmQU=" + }, + "tail": { + "$ref": "AAAAAAFk7D6tiK11uE8=" + }, + "lineStyle": 0, + "points": "840:1168;840:1152;634:1152;634:1108", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7D7FLq9MhrY=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7D7FL69NywQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7D7FL69OLhM=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk7EAL+bwtRL0=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7D/fn7s6PNY=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk7EAL+bwusI8=", + "_parent": { + "$ref": "AAAAAAFk7EAL+bwtRL0=" + }, + "model": { + "$ref": "AAAAAAFk7D/fn7s6PNY=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk7EAL+bwvolk=", + "_parent": { + "$ref": "AAAAAAFk7EAL+bwusI8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1154, + "top": -2750, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7EAL+bwwY/M=", + "_parent": { + "$ref": "AAAAAAFk7EAL+bwusI8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 541, + "top": 1175, + "width": 194, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageProgressIndicator", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7EAL+bwxcVc=", + "_parent": { + "$ref": "AAAAAAFk7EAL+bwusI8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 541, + "top": 1190, + "width": 194, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk7EAL+bwyLtU=", + "_parent": { + "$ref": "AAAAAAFk7EAL+bwusI8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1154, + "top": -2750, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 536, + "top": 1168, + "width": 204, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk7EAL+bwvolk=" + }, + "nameLabel": { + "$ref": "AAAAAAFk7EAL+bwwY/M=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk7EAL+bwxcVc=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7EAL+bwyLtU=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk7EAL+bwz8U8=", + "_parent": { + "$ref": "AAAAAAFk7EAL+bwtRL0=" + }, + "model": { + "$ref": "AAAAAAFk7D/fn7s6PNY=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7ECrWr+BAvQ=", + "_parent": { + "$ref": "AAAAAAFk7EAL+bwz8U8=" + }, + "model": { + "$ref": "AAAAAAFk7ECrIb9dr0E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -51, + "top": -67, + "width": 205.18798828125, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+default", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk7EDMHMGZVlg=", + "_parent": { + "$ref": "AAAAAAFk7EAL+bwz8U8=" + }, + "model": { + "$ref": "AAAAAAFk7EDL38F1+hA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -51, + "top": -52, + "width": 205.18798828125, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+bar", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 536, + "top": 1208, + "width": 215.18798828125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk7EAL+bw0ZP0=", + "_parent": { + "$ref": "AAAAAAFk7EAL+bwtRL0=" + }, + "model": { + "$ref": "AAAAAAFk7D/fn7s6PNY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 536, + "top": 1246, + "width": 215.18798828125, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk7EAL+bw1siU=", + "_parent": { + "$ref": "AAAAAAFk7EAL+bwtRL0=" + }, + "model": { + "$ref": "AAAAAAFk7D/fn7s6PNY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -577, + "top": -1375, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk7EAL+rw23y0=", + "_parent": { + "$ref": "AAAAAAFk7EAL+bwtRL0=" + }, + "model": { + "$ref": "AAAAAAFk7D/fn7s6PNY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -577, + "top": -1375, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 536, + "top": 1168, + "width": 204, + "height": 40, + "autoResize": true, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk7EAL+bwusI8=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk7EAL+bwz8U8=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk7EAL+bw0ZP0=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk7EAL+bw1siU=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk7EAL+rw23y0=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk7EAwILzYtRs=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAFk7EAwILzXek0=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7EAwILzZPlQ=", + "_parent": { + "$ref": "AAAAAAFk7EAwILzYtRs=" + }, + "model": { + "$ref": "AAAAAAFk7EAwILzXek0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 609, + "top": 1131, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7EAwILzYtRs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7EAwIbzaHFM=", + "_parent": { + "$ref": "AAAAAAFk7EAwILzYtRs=" + }, + "model": { + "$ref": "AAAAAAFk7EAwILzXek0=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 594, + "top": 1131, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk7EAwILzYtRs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk7EAwIbzb0dQ=", + "_parent": { + "$ref": "AAAAAAFk7EAwILzYtRs=" + }, + "model": { + "$ref": "AAAAAAFk7EAwILzXek0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 638, + "top": 1132, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk7EAwILzYtRs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk7D1LoKHDmQU=" + }, + "tail": { + "$ref": "AAAAAAFk7EAL+bwtRL0=" + }, + "lineStyle": 0, + "points": "624:1168;624:1108", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk7EAwILzZPlQ=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk7EAwIbzaHFM=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk7EAwIbzb0dQ=" + } + } + ] + }, + { + "_type": "UMLCollaboration", + "_id": "AAAAAAFUkhaWOozRCy8=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Collaboration", + "ownedElements": [ + { + "_type": "UMLInteraction", + "_id": "AAAAAAFUkhaWOozSZjs=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozRCy8=" + }, + "name": "Interaction", + "ownedElements": [ + { + "_type": "UMLSequenceDiagram", + "_id": "AAAAAAFUkhaWOozTHHk=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "Sequence Diagram", + "visible": true, + "defaultDiagram": false, + "ownedViews": [ + { + "_type": "UMLSeqLifelineView", + "_id": "AAAAAAFUv2aES8ybhJ8=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFUv2aES8yaBvg=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUv2aES8ycWzA=", + "_parent": { + "$ref": "AAAAAAFUv2aES8ybhJ8=" + }, + "model": { + "$ref": "AAAAAAFUv2aES8yaBvg=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUv2aETMydAio=", + "_parent": { + "$ref": "AAAAAAFUv2aES8ycWzA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -400, + "top": 0, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv2aETMyekVc=", + "_parent": { + "$ref": "AAAAAAFUv2aES8ycWzA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 47, + "width": 93.33544921875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "Other object", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv2aETcyfM5E=", + "_parent": { + "$ref": "AAAAAAFUv2aES8ycWzA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -400, + "top": 0, + "width": 116.3779296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from Interaction)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv2aETcyg6Xc=", + "_parent": { + "$ref": "AAAAAAFUv2aES8ycWzA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -400, + "top": 0, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 40, + "width": 103.33544921875, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUv2aETMydAio=" + }, + "nameLabel": { + "$ref": "AAAAAAFUv2aETMyekVc=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUv2aETcyfM5E=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUv2aETcyg6Xc=" + } + }, + { + "_type": "UMLLinePartView", + "_id": "AAAAAAFUv2aETcyhhXc=", + "_parent": { + "$ref": "AAAAAAFUv2aES8ybhJ8=" + }, + "model": { + "$ref": "AAAAAAFUv2aES8yaBvg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 68, + "top": 80, + "width": 1, + "height": 399, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 40, + "width": 103.33544921875, + "height": 439, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": false, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUv2aES8ycWzA=" + }, + "wordWrap": false, + "linePart": { + "$ref": "AAAAAAFUv2aETcyhhXc=" + } + }, + { + "_type": "UMLSeqLifelineView", + "_id": "AAAAAAFUv2nXaM1BaOI=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFUv2nXaM1AL0k=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUv2nXaM1CeNE=", + "_parent": { + "$ref": "AAAAAAFUv2nXaM1BaOI=" + }, + "model": { + "$ref": "AAAAAAFUv2nXaM1AL0k=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUv2nXbM1D228=", + "_parent": { + "$ref": "AAAAAAFUv2nXaM1CeNE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1554, + "top": 0, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv2nXbM1ED74=", + "_parent": { + "$ref": "AAAAAAFUv2nXaM1CeNE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 133, + "top": 47, + "width": 245.41064453125, + "height": 13, + "autoResize": false, + "underline": false, + "text": "Lifeline1", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv2nXbM1F5i0=", + "_parent": { + "$ref": "AAAAAAFUv2nXaM1CeNE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1554, + "top": 0, + "width": 116.3779296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from Interaction)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv2nXbM1GtnA=", + "_parent": { + "$ref": "AAAAAAFUv2nXaM1CeNE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1554, + "top": 0, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 128, + "top": 40, + "width": 255.41064453125, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUv2nXbM1D228=" + }, + "nameLabel": { + "$ref": "AAAAAAFUv2nXbM1ED74=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUv2nXbM1F5i0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUv2nXbM1GtnA=" + } + }, + { + "_type": "UMLLinePartView", + "_id": "AAAAAAFUv2nXbM1HcJ0=", + "_parent": { + "$ref": "AAAAAAFUv2nXaM1BaOI=" + }, + "model": { + "$ref": "AAAAAAFUv2nXaM1AL0k=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 256, + "top": 80, + "width": 1, + "height": 399, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 128, + "top": 40, + "width": 255.41064453125, + "height": 439, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": false, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUv2nXaM1CeNE=" + }, + "wordWrap": false, + "linePart": { + "$ref": "AAAAAAFUv2nXbM1HcJ0=" + } + }, + { + "_type": "UMLSeqLifelineView", + "_id": "AAAAAAFUv2n3Rc1gg3I=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFUv2n3Rc1fbGI=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUv2n3Rs1himo=", + "_parent": { + "$ref": "AAAAAAFUv2n3Rc1gg3I=" + }, + "model": { + "$ref": "AAAAAAFUv2n3Rc1fbGI=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUv2n3Rs1i/NA=", + "_parent": { + "$ref": "AAAAAAFUv2n3Rs1himo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1184, + "top": 0, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv2n3Rs1joWc=", + "_parent": { + "$ref": "AAAAAAFUv2n3Rs1himo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 621, + "top": 47, + "width": 219.958984375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "Lifeline3", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv2n3Rs1k/4Q=", + "_parent": { + "$ref": "AAAAAAFUv2n3Rs1himo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1184, + "top": 0, + "width": 116.3779296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from Interaction)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv2n3Rs1lmgQ=", + "_parent": { + "$ref": "AAAAAAFUv2n3Rs1himo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1184, + "top": 0, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 616, + "top": 40, + "width": 229.958984375, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUv2n3Rs1i/NA=" + }, + "nameLabel": { + "$ref": "AAAAAAFUv2n3Rs1joWc=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUv2n3Rs1k/4Q=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUv2n3Rs1lmgQ=" + } + }, + { + "_type": "UMLLinePartView", + "_id": "AAAAAAFUv2n3Rs1mvsI=", + "_parent": { + "$ref": "AAAAAAFUv2n3Rc1gg3I=" + }, + "model": { + "$ref": "AAAAAAFUv2n3Rc1fbGI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 731, + "top": 80, + "width": 1, + "height": 369, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 616, + "top": 40, + "width": 229.958984375, + "height": 409, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": false, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUv2n3Rs1himo=" + }, + "wordWrap": false, + "linePart": { + "$ref": "AAAAAAFUv2n3Rs1mvsI=" + } + }, + { + "_type": "UMLSeqMessageView", + "_id": "AAAAAAFUv2qLR829xEQ=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFUv2qLR828Lgg=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv2qLSM2+Rpk=", + "_parent": { + "$ref": "AAAAAAFUv2qLR829xEQ=" + }, + "model": { + "$ref": "AAAAAAFUv2qLR828Lgg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 81, + "top": 104, + "width": 155.68896484375, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFUv2qLR829xEQ=" + }, + "edgePosition": 1, + "underline": false, + "text": "1 : sd_setImageWithURL()", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv2qLSM2/ZbI=", + "_parent": { + "$ref": "AAAAAAFUv2qLR829xEQ=" + }, + "model": { + "$ref": "AAAAAAFUv2qLR828Lgg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 158, + "top": 89, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFUv2qLR829xEQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv2qLSM3A+iE=", + "_parent": { + "$ref": "AAAAAAFUv2qLR829xEQ=" + }, + "model": { + "$ref": "AAAAAAFUv2qLR828Lgg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 158, + "top": 124, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFUv2qLR829xEQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLActivationView", + "_id": "AAAAAAFUv2qLSM3BCds=", + "_parent": { + "$ref": "AAAAAAFUv2qLR829xEQ=" + }, + "model": { + "$ref": "AAAAAAFUv2qLR828Lgg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 249, + "top": 120, + "width": 14, + "height": 29, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUv2nXbM1HcJ0=" + }, + "tail": { + "$ref": "AAAAAAFUv2aETcyhhXc=" + }, + "lineStyle": 0, + "points": "68:120;249:120", + "nameLabel": { + "$ref": "AAAAAAFUv2qLSM2+Rpk=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFUv2qLSM2/ZbI=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUv2qLSM3A+iE=" + }, + "activation": { + "$ref": "AAAAAAFUv2qLSM3BCds=" + }, + "showProperty": true, + "showType": true + }, + { + "_type": "UMLSeqLifelineView", + "_id": "AAAAAAFUv2ti0c3qqN0=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFUv2ti0c3pnPk=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUv2ti0c3rcoE=", + "_parent": { + "$ref": "AAAAAAFUv2ti0c3qqN0=" + }, + "model": { + "$ref": "AAAAAAFUv2ti0c3pnPk=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUv2ti0s3sWPY=", + "_parent": { + "$ref": "AAAAAAFUv2ti0c3rcoE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -160, + "top": 0, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv2ti0s3tDyM=", + "_parent": { + "$ref": "AAAAAAFUv2ti0c3rcoE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 861, + "top": 47, + "width": 174.23046875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "Lifeline4", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv2ti0s3uihE=", + "_parent": { + "$ref": "AAAAAAFUv2ti0c3rcoE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -160, + "top": 0, + "width": 116.3779296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from Interaction)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv2ti0s3vC6k=", + "_parent": { + "$ref": "AAAAAAFUv2ti0c3rcoE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -160, + "top": 0, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 856, + "top": 40, + "width": 184.23046875, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUv2ti0s3sWPY=" + }, + "nameLabel": { + "$ref": "AAAAAAFUv2ti0s3tDyM=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUv2ti0s3uihE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUv2ti0s3vC6k=" + } + }, + { + "_type": "UMLLinePartView", + "_id": "AAAAAAFUv2ti0s3wcIg=", + "_parent": { + "$ref": "AAAAAAFUv2ti0c3qqN0=" + }, + "model": { + "$ref": "AAAAAAFUv2ti0c3pnPk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 948, + "top": 80, + "width": 1, + "height": 361, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 856, + "top": 40, + "width": 184.23046875, + "height": 401, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": false, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUv2ti0c3rcoE=" + }, + "wordWrap": false, + "linePart": { + "$ref": "AAAAAAFUv2ti0s3wcIg=" + } + }, + { + "_type": "UMLSeqLifelineView", + "_id": "AAAAAAFUv22omM5CQm8=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFUv22omM5BZb4=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFUv22omM5DEW0=", + "_parent": { + "$ref": "AAAAAAFUv22omM5CQm8=" + }, + "model": { + "$ref": "AAAAAAFUv22omM5BZb4=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFUv22omc5E59M=", + "_parent": { + "$ref": "AAAAAAFUv22omM5DEW0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -128, + "top": 0, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv22omc5FYM4=", + "_parent": { + "$ref": "AAAAAAFUv22omM5DEW0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1053, + "top": 47, + "width": 242.912109375, + "height": 13, + "autoResize": false, + "underline": false, + "text": "Lifeline5", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv22omc5GELE=", + "_parent": { + "$ref": "AAAAAAFUv22omM5DEW0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -128, + "top": 0, + "width": 116.3779296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from Interaction)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFUv22omc5HhQ8=", + "_parent": { + "$ref": "AAAAAAFUv22omM5DEW0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -128, + "top": 0, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1048, + "top": 40, + "width": 252.912109375, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFUv22omc5E59M=" + }, + "nameLabel": { + "$ref": "AAAAAAFUv22omc5FYM4=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFUv22omc5GELE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUv22omc5HhQ8=" + } + }, + { + "_type": "UMLLinePartView", + "_id": "AAAAAAFUv22omc5ImFY=", + "_parent": { + "$ref": "AAAAAAFUv22omM5CQm8=" + }, + "model": { + "$ref": "AAAAAAFUv22omM5BZb4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1174, + "top": 80, + "width": 1, + "height": 271, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1048, + "top": 40, + "width": 252.912109375, + "height": 311, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": false, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFUv22omM5DEW0=" + }, + "wordWrap": false, + "linePart": { + "$ref": "AAAAAAFUv22omc5ImFY=" + } + }, + { + "_type": "UMLSeqMessageView", + "_id": "AAAAAAFXmw7K85hmo5Q=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFXmw7K8phl/ns=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmw7K85hnTgg=", + "_parent": { + "$ref": "AAAAAAFXmw7K85hmo5Q=" + }, + "model": { + "$ref": "AAAAAAFXmw7K8phl/ns=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 275, + "top": 120, + "width": 204.318359375, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFXmw7K85hmo5Q=" + }, + "edgePosition": 1, + "underline": false, + "text": "2 : sd_internalSetImageWithURL()", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmw7K85ho9qQ=", + "_parent": { + "$ref": "AAAAAAFXmw7K85hmo5Q=" + }, + "model": { + "$ref": "AAAAAAFXmw7K8phl/ns=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 377, + "top": 105, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFXmw7K85hmo5Q=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmw7K85hpBeU=", + "_parent": { + "$ref": "AAAAAAFXmw7K85hmo5Q=" + }, + "model": { + "$ref": "AAAAAAFXmw7K8phl/ns=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 377, + "top": 140, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFXmw7K85hmo5Q=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLActivationView", + "_id": "AAAAAAFXmw7K85hqA4o=", + "_parent": { + "$ref": "AAAAAAFXmw7K85hmo5Q=" + }, + "model": { + "$ref": "AAAAAAFXmw7K8phl/ns=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 492, + "top": 136, + "width": 14, + "height": 29, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFXmwx1Rpf0Po8=" + }, + "tail": { + "$ref": "AAAAAAFUv2nXbM1HcJ0=" + }, + "lineStyle": 0, + "points": "262:136;492:136", + "nameLabel": { + "$ref": "AAAAAAFXmw7K85hnTgg=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFXmw7K85ho9qQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFXmw7K85hpBeU=" + }, + "activation": { + "$ref": "AAAAAAFXmw7K85hqA4o=" + }, + "showProperty": true, + "showType": true + }, + { + "_type": "UMLSeqMessageView", + "_id": "AAAAAAFXmw++VZh9CRk=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFXmw++VJh8ixo=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmw++VZh+iEI=", + "_parent": { + "$ref": "AAAAAAFXmw++VZh9CRk=" + }, + "model": { + "$ref": "AAAAAAFXmw++VJh8ixo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 472, + "top": 127, + "width": 285, + "height": 26, + "autoResize": false, + "alpha": 1.5707954934615633, + "distance": 12, + "hostEdge": { + "$ref": "AAAAAAFXmw++VZh9CRk=" + }, + "edgePosition": 1, + "underline": false, + "text": "3 : loadImage(url, options, context, progressBlock, completedBlock)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": true + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmw++VZh/8Ys=", + "_parent": { + "$ref": "AAAAAAFXmw++VZh9CRk=" + }, + "model": { + "$ref": "AAAAAAFXmw++VJh8ixo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 614, + "top": 121, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFXmw++VZh9CRk=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmw++VZiAOKg=", + "_parent": { + "$ref": "AAAAAAFXmw++VZh9CRk=" + }, + "model": { + "$ref": "AAAAAAFXmw++VJh8ixo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 614, + "top": 156, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFXmw++VZh9CRk=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLActivationView", + "_id": "AAAAAAFXmw++VZiBUwE=", + "_parent": { + "$ref": "AAAAAAFXmw++VZh9CRk=" + }, + "model": { + "$ref": "AAAAAAFXmw++VJh8ixo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 724, + "top": 152, + "width": 14, + "height": 29, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUv2n3Rs1mvsI=" + }, + "tail": { + "$ref": "AAAAAAFXmwx1Rpf0Po8=" + }, + "lineStyle": 0, + "points": "505:152;724:152", + "nameLabel": { + "$ref": "AAAAAAFXmw++VZh+iEI=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFXmw++VZh/8Ys=" + }, + "propertyLabel": { + "$ref": "AAAAAAFXmw++VZiAOKg=" + }, + "activation": { + "$ref": "AAAAAAFXmw++VZiBUwE=" + }, + "showProperty": true, + "showType": true + }, + { + "_type": "UMLSeqMessageView", + "_id": "AAAAAAFUv2v1XM4K3QQ=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFUv2v1XM4JR/4=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv2v1XM4L7pY=", + "_parent": { + "$ref": "AAAAAAFUv2v1XM4K3QQ=" + }, + "model": { + "$ref": "AAAAAAFUv2v1XM4JR/4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 720, + "top": 142, + "width": 249, + "height": 26, + "autoResize": false, + "alpha": 1.2036218228737574, + "distance": 13.92838827718412, + "hostEdge": { + "$ref": "AAAAAAFUv2v1XM4K3QQ=" + }, + "edgePosition": 1, + "underline": false, + "text": "4 : queryImage(key, options, context, completionBlock)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": true + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv2v1Xc4MPnU=", + "_parent": { + "$ref": "AAAAAAFUv2v1XM4K3QQ=" + }, + "model": { + "$ref": "AAAAAAFUv2v1XM4JR/4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 839, + "top": 137, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFUv2v1XM4K3QQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv2v1Xc4NX9s=", + "_parent": { + "$ref": "AAAAAAFUv2v1XM4K3QQ=" + }, + "model": { + "$ref": "AAAAAAFUv2v1XM4JR/4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 839, + "top": 172, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFUv2v1XM4K3QQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLActivationView", + "_id": "AAAAAAFUv2v1Xc4OIGU=", + "_parent": { + "$ref": "AAAAAAFUv2v1XM4K3QQ=" + }, + "model": { + "$ref": "AAAAAAFUv2v1XM4JR/4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 941, + "top": 168, + "width": 14, + "height": 29, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUv2ti0s3wcIg=" + }, + "tail": { + "$ref": "AAAAAAFUv2n3Rs1mvsI=" + }, + "lineStyle": 0, + "points": "737:168;941:168", + "nameLabel": { + "$ref": "AAAAAAFUv2v1XM4L7pY=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFUv2v1Xc4MPnU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUv2v1Xc4NX9s=" + }, + "activation": { + "$ref": "AAAAAAFUv2v1Xc4OIGU=" + }, + "showProperty": true, + "showType": true + }, + { + "_type": "UMLSeqMessageView", + "_id": "AAAAAAFUv2z30M4lNWE=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFUv2z3z84kqYU=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv2z30M4mUAU=", + "_parent": { + "$ref": "AAAAAAFUv2z30M4lNWE=" + }, + "model": { + "$ref": "AAAAAAFUv2z3z84kqYU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 798, + "top": 212, + "width": 81.90380859375, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFUv2z30M4lNWE=" + }, + "edgePosition": 1, + "underline": false, + "text": "5 : disk result", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv2z30M4nw8c=", + "_parent": { + "$ref": "AAAAAAFUv2z30M4lNWE=" + }, + "model": { + "$ref": "AAAAAAFUv2z3z84kqYU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 838, + "top": 227, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFUv2z30M4lNWE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv2z30M4odbY=", + "_parent": { + "$ref": "AAAAAAFUv2z30M4lNWE=" + }, + "model": { + "$ref": "AAAAAAFUv2z3z84kqYU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 839, + "top": 192, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFUv2z30M4lNWE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLActivationView", + "_id": "AAAAAAFUv2z30c4pSow=", + "_parent": { + "$ref": "AAAAAAFUv2z30M4lNWE=" + }, + "model": { + "$ref": "AAAAAAFUv2z3z84kqYU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 731, + "top": 208, + "width": 14, + "height": 25, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUv2n3Rs1mvsI=" + }, + "tail": { + "$ref": "AAAAAAFUv2ti0s3wcIg=" + }, + "lineStyle": 0, + "points": "948:208;731:208", + "nameLabel": { + "$ref": "AAAAAAFUv2z30M4mUAU=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFUv2z30M4nw8c=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUv2z30M4odbY=" + }, + "activation": { + "$ref": "AAAAAAFUv2z30c4pSow=" + }, + "showProperty": true, + "showType": true + }, + { + "_type": "UMLSeqMessageView", + "_id": "AAAAAAFUv235TM5iC/o=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFUv235TM5h8OU=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv235Tc5jIuU=", + "_parent": { + "$ref": "AAAAAAFUv235TM5iC/o=" + }, + "model": { + "$ref": "AAAAAAFUv235TM5h8OU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 736, + "top": 246, + "width": 213, + "height": 26, + "autoResize": false, + "alpha": -3.2532755257807673, + "distance": 107.67079455451233, + "hostEdge": { + "$ref": "AAAAAAFUv235TM5iC/o=" + }, + "edgePosition": 1, + "underline": false, + "text": "6 : loadImage(url, options, context, progressBlock, completedBlock)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": true + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv235Tc5kvxw=", + "_parent": { + "$ref": "AAAAAAFUv235TM5iC/o=" + }, + "model": { + "$ref": "AAAAAAFUv235TM5h8OU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 949, + "top": 241, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFUv235TM5iC/o=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv235Tc5lN1Y=", + "_parent": { + "$ref": "AAAAAAFUv235TM5iC/o=" + }, + "model": { + "$ref": "AAAAAAFUv235TM5h8OU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 949, + "top": 276, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFUv235TM5iC/o=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLActivationView", + "_id": "AAAAAAFUv235Tc5mBt8=", + "_parent": { + "$ref": "AAAAAAFUv235TM5iC/o=" + }, + "model": { + "$ref": "AAAAAAFUv235TM5h8OU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1167, + "top": 272, + "width": 14, + "height": 29, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUv22omc5ImFY=" + }, + "tail": { + "$ref": "AAAAAAFUv2n3Rs1mvsI=" + }, + "lineStyle": 0, + "points": "731:272;1167:272", + "nameLabel": { + "$ref": "AAAAAAFUv235Tc5jIuU=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFUv235Tc5kvxw=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUv235Tc5lN1Y=" + }, + "activation": { + "$ref": "AAAAAAFUv235Tc5mBt8=" + }, + "showProperty": true, + "showType": true + }, + { + "_type": "UMLSeqMessageView", + "_id": "AAAAAAFUv27NWM56DH8=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFUv27NV855tyI=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv27NWM57KC8=", + "_parent": { + "$ref": "AAAAAAFUv27NWM56DH8=" + }, + "model": { + "$ref": "AAAAAAFUv27NV855tyI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 976, + "top": 323, + "width": 106.8310546875, + "height": 13, + "autoResize": false, + "alpha": 3.0124453800482693, + "distance": 77.64663547121665, + "hostEdge": { + "$ref": "AAAAAAFUv27NWM56DH8=" + }, + "edgePosition": 1, + "underline": false, + "text": "7 : network result", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv27NWM58Rks=", + "_parent": { + "$ref": "AAAAAAFUv27NWM56DH8=" + }, + "model": { + "$ref": "AAAAAAFUv27NV855tyI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 951, + "top": 339, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFUv27NWM56DH8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv27NWc59ep8=", + "_parent": { + "$ref": "AAAAAAFUv27NWM56DH8=" + }, + "model": { + "$ref": "AAAAAAFUv27NV855tyI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 952, + "top": 304, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFUv27NWM56DH8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLActivationView", + "_id": "AAAAAAFUv27NWc5+otg=", + "_parent": { + "$ref": "AAAAAAFUv27NWM56DH8=" + }, + "model": { + "$ref": "AAAAAAFUv27NV855tyI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 731, + "top": 320, + "width": 14, + "height": 25, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUv2n3Rs1mvsI=" + }, + "tail": { + "$ref": "AAAAAAFUv22omc5ImFY=" + }, + "lineStyle": 0, + "points": "1174:320;731:320", + "nameLabel": { + "$ref": "AAAAAAFUv27NWM57KC8=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFUv27NWM58Rks=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUv27NWc59ep8=" + }, + "activation": { + "$ref": "AAAAAAFUv27NWc5+otg=" + }, + "showProperty": true, + "showType": true + }, + { + "_type": "UMLSeqLifelineView", + "_id": "AAAAAAFXmwx1RpfuYEQ=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFXmwx1Rpft3W0=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFXmwx1Rpfvk4E=", + "_parent": { + "$ref": "AAAAAAFXmwx1RpfuYEQ=" + }, + "model": { + "$ref": "AAAAAAFXmwx1Rpft3W0=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFXmwx1Rpfwxbg=", + "_parent": { + "$ref": "AAAAAAFXmwx1Rpfvk4E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -132, + "top": 0, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmwx1RpfxG9g=", + "_parent": { + "$ref": "AAAAAAFXmwx1Rpfvk4E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 397, + "top": 47, + "width": 204.65869140625, + "height": 13, + "autoResize": false, + "underline": false, + "text": "Lifeline2", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmwx1Rpfyq/k=", + "_parent": { + "$ref": "AAAAAAFXmwx1Rpfvk4E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -132, + "top": 0, + "width": 116.3779296875, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from Interaction)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFXmwx1RpfzQBw=", + "_parent": { + "$ref": "AAAAAAFXmwx1Rpfvk4E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -132, + "top": 0, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 392, + "top": 40, + "width": 214.65869140625, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFXmwx1Rpfwxbg=" + }, + "nameLabel": { + "$ref": "AAAAAAFXmwx1RpfxG9g=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFXmwx1Rpfyq/k=" + }, + "propertyLabel": { + "$ref": "AAAAAAFXmwx1RpfzQBw=" + } + }, + { + "_type": "UMLLinePartView", + "_id": "AAAAAAFXmwx1Rpf0Po8=", + "_parent": { + "$ref": "AAAAAAFXmwx1RpfuYEQ=" + }, + "model": { + "$ref": "AAAAAAFXmwx1Rpft3W0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 499, + "top": 80, + "width": 1, + "height": 375, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 392, + "top": 40, + "width": 214.65869140625, + "height": 415, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": false, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFXmwx1Rpfvk4E=" + }, + "wordWrap": false, + "linePart": { + "$ref": "AAAAAAFXmwx1Rpf0Po8=" + } + }, + { + "_type": "UMLSeqMessageView", + "_id": "AAAAAAFUv3C4p87cxD0=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFUv3C4p87b5L8=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv3C4qM7dheQ=", + "_parent": { + "$ref": "AAAAAAFUv3C4p87cxD0=" + }, + "model": { + "$ref": "AAAAAAFUv3C4p87b5L8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 720, + "top": 346, + "width": 232, + "height": 26, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFUv3C4p87cxD0=" + }, + "edgePosition": 1, + "underline": false, + "text": "8 : store(image, imageData, key, toDisk, completionBlock)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": true + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv3C4qM7eLhs=", + "_parent": { + "$ref": "AAAAAAFUv3C4p87cxD0=" + }, + "model": { + "$ref": "AAAAAAFUv3C4p87b5L8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 836, + "top": 338, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFUv3C4p87cxD0=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFUv3C4qM7fGpA=", + "_parent": { + "$ref": "AAAAAAFUv3C4p87cxD0=" + }, + "model": { + "$ref": "AAAAAAFUv3C4p87b5L8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 836, + "top": 373, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFUv3C4p87cxD0=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLActivationView", + "_id": "AAAAAAFUv3C4qM7gDWs=", + "_parent": { + "$ref": "AAAAAAFUv3C4p87cxD0=" + }, + "model": { + "$ref": "AAAAAAFUv3C4p87b5L8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 941, + "top": 369, + "width": 14, + "height": 29, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUv2ti0s3wcIg=" + }, + "tail": { + "$ref": "AAAAAAFUv2n3Rs1mvsI=" + }, + "lineStyle": 0, + "points": "731:369;941:369", + "nameLabel": { + "$ref": "AAAAAAFUv3C4qM7dheQ=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFUv3C4qM7eLhs=" + }, + "propertyLabel": { + "$ref": "AAAAAAFUv3C4qM7fGpA=" + }, + "activation": { + "$ref": "AAAAAAFUv3C4qM7gDWs=" + }, + "showProperty": true, + "showType": true + }, + { + "_type": "UMLSeqMessageView", + "_id": "AAAAAAFXmxBoRJiUpvI=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFXmxBoRJiTAtY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmxBoRZiVYHw=", + "_parent": { + "$ref": "AAAAAAFXmxBoRJiUpvI=" + }, + "model": { + "$ref": "AAAAAAFXmxBoRJiTAtY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 587, + "top": 404, + "width": 55.0341796875, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFXmxBoRJiUpvI=" + }, + "edgePosition": 1, + "underline": false, + "text": "9 : image", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmxBoRZiWIYg=", + "_parent": { + "$ref": "AAAAAAFXmxBoRJiUpvI=" + }, + "model": { + "$ref": "AAAAAAFXmxBoRJiTAtY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 614, + "top": 419, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFXmxBoRJiUpvI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmxBoRZiXh28=", + "_parent": { + "$ref": "AAAAAAFXmxBoRJiUpvI=" + }, + "model": { + "$ref": "AAAAAAFXmxBoRJiTAtY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 615, + "top": 384, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFXmxBoRJiUpvI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLActivationView", + "_id": "AAAAAAFXmxBoRZiYI2g=", + "_parent": { + "$ref": "AAAAAAFXmxBoRJiUpvI=" + }, + "model": { + "$ref": "AAAAAAFXmxBoRJiTAtY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 499, + "top": 400, + "width": 14, + "height": 25, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFXmwx1Rpf0Po8=" + }, + "tail": { + "$ref": "AAAAAAFUv2n3Rs1mvsI=" + }, + "lineStyle": 0, + "points": "731:400;499:400", + "nameLabel": { + "$ref": "AAAAAAFXmxBoRZiVYHw=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFXmxBoRZiWIYg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFXmxBoRZiXh28=" + }, + "activation": { + "$ref": "AAAAAAFXmxBoRZiYI2g=" + }, + "showProperty": true, + "showType": true + }, + { + "_type": "UMLSeqMessageView", + "_id": "AAAAAAFXmxC8H5jJURo=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozTHHk=" + }, + "model": { + "$ref": "AAAAAAFXmxC8H5jIbu4=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmxC8H5jKD8g=", + "_parent": { + "$ref": "AAAAAAFXmxC8H5jJURo=" + }, + "model": { + "$ref": "AAAAAAFXmxC8H5jIbu4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 335, + "top": 428, + "width": 83.51611328125, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFXmxC8H5jJURo=" + }, + "edgePosition": 1, + "underline": false, + "text": "10 : set image", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmxC8H5jLiWU=", + "_parent": { + "$ref": "AAAAAAFXmxC8H5jJURo=" + }, + "model": { + "$ref": "AAAAAAFXmxC8H5jIbu4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 376, + "top": 443, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFXmxC8H5jJURo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFXmxC8H5jMFqs=", + "_parent": { + "$ref": "AAAAAAFXmxC8H5jJURo=" + }, + "model": { + "$ref": "AAAAAAFXmxC8H5jIbu4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 377, + "top": 408, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 10, + "hostEdge": { + "$ref": "AAAAAAFXmxC8H5jJURo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLActivationView", + "_id": "AAAAAAFXmxC8H5jNKho=", + "_parent": { + "$ref": "AAAAAAFXmxC8H5jJURo=" + }, + "model": { + "$ref": "AAAAAAFXmxC8H5jIbu4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 256, + "top": 424, + "width": 14, + "height": 25, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFUv2nXbM1HcJ0=" + }, + "tail": { + "$ref": "AAAAAAFXmwx1Rpf0Po8=" + }, + "lineStyle": 0, + "points": "499:424;256:424", + "nameLabel": { + "$ref": "AAAAAAFXmxC8H5jKD8g=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFXmxC8H5jLiWU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFXmxC8H5jMFqs=" + }, + "activation": { + "$ref": "AAAAAAFXmxC8H5jNKho=" + }, + "showProperty": true, + "showType": true + } + ], + "showSequenceNumber": true, + "showSignature": true, + "showActivation": true + } + ], + "visibility": "public", + "isReentrant": true, + "messages": [ + { + "_type": "UMLMessage", + "_id": "AAAAAAFUv2qLR828Lgg=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "Message1", + "source": { + "$ref": "AAAAAAFUv2aES8yaBvg=" + }, + "target": { + "$ref": "AAAAAAFUv2nXaM1AL0k=" + }, + "visibility": "public", + "messageSort": "asynchCall", + "signature": { + "$ref": "AAAAAAFUmPuK4C6yWrI=" + }, + "isConcurrentIteration": false + }, + { + "_type": "UMLMessage", + "_id": "AAAAAAFXmw7K8phl/ns=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "Message2", + "source": { + "$ref": "AAAAAAFUv2nXaM1AL0k=" + }, + "target": { + "$ref": "AAAAAAFXmwx1Rpft3W0=" + }, + "visibility": "public", + "messageSort": "asynchCall", + "signature": { + "$ref": "AAAAAAFXmsqK3idvzv0=" + }, + "isConcurrentIteration": false + }, + { + "_type": "UMLMessage", + "_id": "AAAAAAFXmw++VJh8ixo=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "Message6", + "source": { + "$ref": "AAAAAAFXmwx1Rpft3W0=" + }, + "target": { + "$ref": "AAAAAAFUv2n3Rc1fbGI=" + }, + "visibility": "public", + "messageSort": "asynchCall", + "signature": { + "$ref": "AAAAAAFUkh/xZ44AqYk=" + }, + "isConcurrentIteration": false + }, + { + "_type": "UMLMessage", + "_id": "AAAAAAFUv2v1XM4JR/4=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "Message3", + "source": { + "$ref": "AAAAAAFUv2n3Rc1fbGI=" + }, + "target": { + "$ref": "AAAAAAFUv2ti0c3pnPk=" + }, + "visibility": "public", + "messageSort": "asynchCall", + "signature": { + "$ref": "AAAAAAFkzOhe6QsQ8iE=" + }, + "isConcurrentIteration": false + }, + { + "_type": "UMLMessage", + "_id": "AAAAAAFUv2z3z84kqYU=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "disk result", + "source": { + "$ref": "AAAAAAFUv2ti0c3pnPk=" + }, + "target": { + "$ref": "AAAAAAFUv2n3Rc1fbGI=" + }, + "visibility": "public", + "messageSort": "reply", + "isConcurrentIteration": false + }, + { + "_type": "UMLMessage", + "_id": "AAAAAAFUv235TM5h8OU=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "Message4", + "source": { + "$ref": "AAAAAAFUv2n3Rc1fbGI=" + }, + "target": { + "$ref": "AAAAAAFUv22omM5BZb4=" + }, + "visibility": "public", + "messageSort": "asynchCall", + "signature": { + "$ref": "AAAAAAFky3CxVms3ePA=" + }, + "isConcurrentIteration": false + }, + { + "_type": "UMLMessage", + "_id": "AAAAAAFUv27NV855tyI=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "network result", + "source": { + "$ref": "AAAAAAFUv22omM5BZb4=" + }, + "target": { + "$ref": "AAAAAAFUv2n3Rc1fbGI=" + }, + "visibility": "public", + "messageSort": "reply", + "isConcurrentIteration": false + }, + { + "_type": "UMLMessage", + "_id": "AAAAAAFUv3C4p87b5L8=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "Message5", + "source": { + "$ref": "AAAAAAFUv2n3Rc1fbGI=" + }, + "target": { + "$ref": "AAAAAAFUv2ti0c3pnPk=" + }, + "visibility": "public", + "messageSort": "synchCall", + "signature": { + "$ref": "AAAAAAFUmPMOWiHsOa0=" + }, + "isConcurrentIteration": false + }, + { + "_type": "UMLMessage", + "_id": "AAAAAAFXmxBoRJiTAtY=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "image", + "source": { + "$ref": "AAAAAAFUv2n3Rc1fbGI=" + }, + "target": { + "$ref": "AAAAAAFXmwx1Rpft3W0=" + }, + "visibility": "public", + "messageSort": "reply", + "isConcurrentIteration": false + }, + { + "_type": "UMLMessage", + "_id": "AAAAAAFXmxC8H5jIbu4=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "set image", + "source": { + "$ref": "AAAAAAFXmwx1Rpft3W0=" + }, + "target": { + "$ref": "AAAAAAFUv2nXaM1AL0k=" + }, + "visibility": "public", + "messageSort": "reply", + "isConcurrentIteration": false + } + ], + "participants": [ + { + "_type": "UMLLifeline", + "_id": "AAAAAAFUv2aES8yaBvg=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "Other object", + "visibility": "public", + "isMultiInstance": false + }, + { + "_type": "UMLLifeline", + "_id": "AAAAAAFUv2nXaM1AL0k=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "Lifeline1", + "visibility": "public", + "isMultiInstance": false + }, + { + "_type": "UMLLifeline", + "_id": "AAAAAAFUv2n3Rc1fbGI=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "Lifeline3", + "visibility": "public", + "isMultiInstance": false + }, + { + "_type": "UMLLifeline", + "_id": "AAAAAAFUv2ti0c3pnPk=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "Lifeline4", + "visibility": "public", + "isMultiInstance": false + }, + { + "_type": "UMLLifeline", + "_id": "AAAAAAFUv22omM5BZb4=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "Lifeline5", + "visibility": "public", + "isMultiInstance": false + }, + { + "_type": "UMLLifeline", + "_id": "AAAAAAFXmwx1Rpft3W0=", + "_parent": { + "$ref": "AAAAAAFUkhaWOozSZjs=" + }, + "name": "Lifeline2", + "visibility": "public", + "isMultiInstance": false + } + ] + } + ], + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLPackage", + "_id": "AAAAAAFUkhbx4ozg49g=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "SDWebImage", + "ownedElements": [ + { + "_type": "UMLInterface", + "_id": "AAAAAAFk7Cj0NKGudXg=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDAnimatedImage", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7DBYBDxD/3s=", + "_parent": { + "$ref": "AAAAAAFk7Cj0NKGudXg=" + }, + "source": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "target": { + "$ref": "AAAAAAFk7Cj0NKGudXg=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7Cm8PqY2Qm8=", + "_parent": { + "$ref": "AAAAAAFk7Cj0NKGudXg=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7CneCadLYYY=", + "_parent": { + "$ref": "AAAAAAFk7Cm8PqY2Qm8=" + }, + "name": "animatedCoder", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7CnuH6g/bpE=", + "_parent": { + "$ref": "AAAAAAFk7Cm8PqY2Qm8=" + }, + "name": "scale", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7CoQ7KkzMJ4=", + "_parent": { + "$ref": "AAAAAAFk7Cj0NKGudXg=" + }, + "name": "preloadAllFrames", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7CovjqqiyHk=", + "_parent": { + "$ref": "AAAAAAFk7Cj0NKGudXg=" + }, + "name": "unloadAllFrames", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7CpKoKwRISY=", + "_parent": { + "$ref": "AAAAAAFk7Cj0NKGudXg=" + }, + "name": "isAllFramesLoaded", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7Cp5Ya0mPTo=", + "_parent": { + "$ref": "AAAAAAFk7CpKoKwRISY=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Bool", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFky0kNeqcckGY=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDAnimatedImageCoder", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAFk738aHFS48u4=", + "_parent": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "source": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "target": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "visibility": "public" + }, + { + "_type": "UMLGeneralization", + "_id": "AAAAAAFk73/PXlUQYl8=", + "_parent": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "source": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "target": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFky0rWqbVSTp8=", + "_parent": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky0sgWrcohVY=", + "_parent": { + "$ref": "AAAAAAFky0rWqbVSTp8=" + }, + "name": "data", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky0rr6bZM6kQ=", + "_parent": { + "$ref": "AAAAAAFky0rWqbVSTp8=" + }, + "name": "options", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFky0S/MZVxPY0=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDAnimatedImageProvider", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAFk7ClkOKPpj1g=", + "_parent": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "source": { + "$ref": "AAAAAAFk7Cj0NKGudXg=" + }, + "target": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFky0WaTJkCiCI=", + "_parent": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "name": "animatedImageData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky0X21Zn8E68=", + "_parent": { + "$ref": "AAAAAAFky0WaTJkCiCI=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Data", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky0bXOZxXYmQ=", + "_parent": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "name": "animatedImageFrameCount", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky0cWaZ1R3wo=", + "_parent": { + "$ref": "AAAAAAFky0bXOZxXYmQ=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UInt", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky0d4BJ5ka1A=", + "_parent": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "name": "animatedImageLoopCount", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky0eIJp9eueg=", + "_parent": { + "$ref": "AAAAAAFky0d4BJ5ka1A=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UInt", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky0fVlaBxwo0=", + "_parent": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "name": "animatedImageFrame", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky0fpXqFr2lM=", + "_parent": { + "$ref": "AAAAAAFky0fVlaBxwo0=" + }, + "name": "index", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky0gNPaJHYAY=", + "_parent": { + "$ref": "AAAAAAFky0fVlaBxwo0=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UIImage", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky0hX/6NafH4=", + "_parent": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "name": "animatedImageDuration", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky0hvAKRUQ6Q=", + "_parent": { + "$ref": "AAAAAAFky0hX/6NafH4=" + }, + "name": "index", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky0iTGKUwUak=", + "_parent": { + "$ref": "AAAAAAFky0hX/6NafH4=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UInt", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFk0OkMLX851sM=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDDiskCache", + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0Ol/z4IFWS0=", + "_parent": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0OmU/4M1QFY=", + "_parent": { + "$ref": "AAAAAAFk0Ol/z4IFWS0=" + }, + "name": "cachePath", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0OnDOISEB7g=", + "_parent": { + "$ref": "AAAAAAFk0Ol/z4IFWS0=" + }, + "name": "config", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0OnkkIWQSuA=", + "_parent": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "name": "containsData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0On+cIbA6U8=", + "_parent": { + "$ref": "AAAAAAFk0OnkkIWQSuA=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0OoRyYfMmeY=", + "_parent": { + "$ref": "AAAAAAFk0OnkkIWQSuA=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Bool", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0OpCIYkbyn4=", + "_parent": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "name": "data", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0OpSQopLk4g=", + "_parent": { + "$ref": "AAAAAAFk0OpCIYkbyn4=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0OpwIotX70c=", + "_parent": { + "$ref": "AAAAAAFk0OpCIYkbyn4=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Data", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0OrYDIym0yM=", + "_parent": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "name": "setData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0Orv/Y3WyCw=", + "_parent": { + "$ref": "AAAAAAFk0OrYDIym0yM=" + }, + "name": "data", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0OsBTo7i2Iw=", + "_parent": { + "$ref": "AAAAAAFk0OrYDIym0yM=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0OsjbY/ujGE=", + "_parent": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "name": "removeData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0Os19pEeUh4=", + "_parent": { + "$ref": "AAAAAAFk0OsjbY/ujGE=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0OtXrZIqqoc=", + "_parent": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "name": "removeAllData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0Otz15O9b20=", + "_parent": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "name": "removeExpiredData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0OuYl5VQkGk=", + "_parent": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "name": "cachePath", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0OupR5aA2zk=", + "_parent": { + "$ref": "AAAAAAFk0OuYl5VQkGk=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0Ov+CJkfSRI=", + "_parent": { + "$ref": "AAAAAAFk0OuYl5VQkGk=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "String", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0Ovfd5eMoXg=", + "_parent": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "name": "totalCount", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0Own4Zpu7OE=", + "_parent": { + "$ref": "AAAAAAFk0Ovfd5eMoXg=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UInt", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0OxV6pu94G8=", + "_parent": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "name": "totalSize", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0Oxr0pztoVs=", + "_parent": { + "$ref": "AAAAAAFk0OxV6pu94G8=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UInt", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFkzOdOrAhsolg=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageCache", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7Ae0KaF0uoo=", + "_parent": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "source": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "target": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "visibility": "public" + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAFk74en/WM7cFM=", + "_parent": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "source": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "target": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFkzOhe6QsQ8iE=", + "_parent": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "name": "queryImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOiAoQwK7YI=", + "_parent": { + "$ref": "AAAAAAFkzOhe6QsQ8iE=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOiytgzm0FQ=", + "_parent": { + "$ref": "AAAAAAFkzOhe6QsQ8iE=" + }, + "name": "options", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOjQ4A3Cn/4=", + "_parent": { + "$ref": "AAAAAAFkzOhe6QsQ8iE=" + }, + "name": "context", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOjwlw6e/eE=", + "_parent": { + "$ref": "AAAAAAFkzOhe6QsQ8iE=" + }, + "name": "completionBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOkcJA96dIc=", + "_parent": { + "$ref": "AAAAAAFkzOhe6QsQ8iE=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFkzOmFQhJb/sw=", + "_parent": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "name": "store", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOmnchNV/40=", + "_parent": { + "$ref": "AAAAAAFkzOmFQhJb/sw=" + }, + "name": "image", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOnC0xQxm9E=", + "_parent": { + "$ref": "AAAAAAFkzOmFQhJb/sw=" + }, + "name": "imageData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOngfBUN1HI=", + "_parent": { + "$ref": "AAAAAAFkzOmFQhJb/sw=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOoAqxXp+mc=", + "_parent": { + "$ref": "AAAAAAFkzOmFQhJb/sw=" + }, + "name": "cacheType", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOoeRhbFl6k=", + "_parent": { + "$ref": "AAAAAAFkzOmFQhJb/sw=" + }, + "name": "completionBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFkzOpiQxehydI=", + "_parent": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "name": "removeImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOqKChib6i8=", + "_parent": { + "$ref": "AAAAAAFkzOpiQxehydI=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOqlhBl329w=", + "_parent": { + "$ref": "AAAAAAFkzOpiQxehydI=" + }, + "name": "cacheType", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOrFnxpTiGs=", + "_parent": { + "$ref": "AAAAAAFkzOpiQxehydI=" + }, + "name": "completionBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFkzOrxchsvmU0=", + "_parent": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "name": "containsImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOss/R0FYl8=", + "_parent": { + "$ref": "AAAAAAFkzOrxchsvmU0=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOtl7x3h1V4=", + "_parent": { + "$ref": "AAAAAAFkzOrxchsvmU0=" + }, + "name": "cacheType", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOuUmh69bNg=", + "_parent": { + "$ref": "AAAAAAFkzOrxchsvmU0=" + }, + "name": "completionBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFkzOvaYx+Z2C8=", + "_parent": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "name": "clear", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOv4+iCTPnQ=", + "_parent": { + "$ref": "AAAAAAFkzOvaYx+Z2C8=" + }, + "name": "cacheType", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFkzOwWryFvWqM=", + "_parent": { + "$ref": "AAAAAAFkzOvaYx+Z2C8=" + }, + "name": "completionBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFfKte+K96ya3s=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageCoder", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFfKu3J8hGXH0g=", + "_parent": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "source": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "target": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFfKu8vtRgLlUU=", + "_parent": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "source": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "target": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFfKtg9W998WOc=", + "_parent": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "name": "canDecode", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKtmVHeA1m00=", + "_parent": { + "$ref": "AAAAAAFfKtg9W998WOc=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Bool", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKt/Vs+e/T58=", + "_parent": { + "$ref": "AAAAAAFfKtg9W998WOc=" + }, + "name": "data", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFfKtrKNePvsF8=", + "_parent": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "name": "decodedImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKts3/uThE8I=", + "_parent": { + "$ref": "AAAAAAFfKtrKNePvsF8=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UIImage", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKuBV2+icmFY=", + "_parent": { + "$ref": "AAAAAAFfKtrKNePvsF8=" + }, + "name": "data", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFkyzSA6msP6Jo=", + "_parent": { + "$ref": "AAAAAAFfKtrKNePvsF8=" + }, + "name": "options", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFfKuUPYO6usi8=", + "_parent": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "name": "canEncode", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKuVH0O9XDn4=", + "_parent": { + "$ref": "AAAAAAFfKuUPYO6usi8=" + }, + "name": "format", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKuVrIe/rxRg=", + "_parent": { + "$ref": "AAAAAAFfKuUPYO6usi8=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Bool", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFfKuW6ofDJluc=", + "_parent": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "name": "encodedData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKuXdAfFy850=", + "_parent": { + "$ref": "AAAAAAFfKuW6ofDJluc=" + }, + "name": "image", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKuYFWfIGIs0=", + "_parent": { + "$ref": "AAAAAAFfKuW6ofDJluc=" + }, + "name": "format", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKuYeevKaklM=", + "_parent": { + "$ref": "AAAAAAFfKuW6ofDJluc=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Data", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky0CLKYsOi1E=", + "_parent": { + "$ref": "AAAAAAFfKuW6ofDJluc=" + }, + "name": "options", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFky29m0WRt7Q8=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageLoader", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7AFZvlix+G0=", + "_parent": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "source": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "target": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk73Wx7ywf4cU=", + "_parent": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "source": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "target": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "visibility": "public" + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAFk74+x9HmjbAc=", + "_parent": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "source": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "target": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFky3AzTGhO/lc=", + "_parent": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "name": "canLoad", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky3BFXWlIW2A=", + "_parent": { + "$ref": "AAAAAAFky3AzTGhO/lc=" + }, + "name": "url", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky3BcPWokz5M=", + "_parent": { + "$ref": "AAAAAAFky3AzTGhO/lc=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Bool", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky3CxVms3ePA=", + "_parent": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "name": "loadImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky3DW3mwxht4=", + "_parent": { + "$ref": "AAAAAAFky3CxVms3ePA=" + }, + "name": "url", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky3D1320N2l8=", + "_parent": { + "$ref": "AAAAAAFky3CxVms3ePA=" + }, + "name": "options", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky3HZk23pG2A=", + "_parent": { + "$ref": "AAAAAAFky3CxVms3ePA=" + }, + "name": "context", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky3H0w27FLt8=", + "_parent": { + "$ref": "AAAAAAFky3CxVms3ePA=" + }, + "name": "progressBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky3IVvG+hZE4=", + "_parent": { + "$ref": "AAAAAAFky3CxVms3ePA=" + }, + "name": "completedBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky3I33XB9zX4=", + "_parent": { + "$ref": "AAAAAAFky3CxVms3ePA=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFk0OQoUmOmW5c=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDMemoryCache", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAFk74lfE2kn7IU=", + "_parent": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk74lfE2kond4=", + "_parent": { + "$ref": "AAAAAAFk74lfE2kn7IU=" + }, + "reference": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "none", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk74lfE2kppRA=", + "_parent": { + "$ref": "AAAAAAFk74lfE2kn7IU=" + }, + "reference": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "shared", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "visibility": "public", + "isDerived": false + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0OSfa2QT4IA=", + "_parent": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0OS0A2R63nU=", + "_parent": { + "$ref": "AAAAAAFk0OSfa2QT4IA=" + }, + "name": "config", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0OTdZGUCETU=", + "_parent": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "name": "object", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0OTtbGVp8Go=", + "_parent": { + "$ref": "AAAAAAFk0OTdZGUCETU=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0OUR7WXxHho=", + "_parent": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "name": "setObject", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0OUiTWZYWHg=", + "_parent": { + "$ref": "AAAAAAFk0OUR7WXxHho=" + }, + "name": "object", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0OVAfmbgRmA=", + "_parent": { + "$ref": "AAAAAAFk0OUR7WXxHho=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0OV/1mdoXvY=", + "_parent": { + "$ref": "AAAAAAFk0OUR7WXxHho=" + }, + "name": "cost", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0OWj72fwP7o=", + "_parent": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "name": "removeObject", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0OWzn2hXX8I=", + "_parent": { + "$ref": "AAAAAAFk0OWj72fwP7o=" + }, + "name": "object", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0OXRGGjfriQ=", + "_parent": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "name": "removeAllObjects", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFfKuaHevMvVkQ=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDProgressiveImageCoder", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAFfKutJugVRytg=", + "_parent": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "source": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "target": { + "$ref": "AAAAAAFk0ObxVHApLxs=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFfKu+znBqqvWQ=", + "_parent": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "source": { + "$ref": "AAAAAAFfKul3rf0/okM=" + }, + "target": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFfKu/8NRxLVBY=", + "_parent": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "source": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "target": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "visibility": "public" + }, + { + "_type": "UMLGeneralization", + "_id": "AAAAAAFk73/AjVT/3Vw=", + "_parent": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "source": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "target": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFfKudnG/biyzM=", + "_parent": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "name": "canIncrementalDecode", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKuexY/hArUE=", + "_parent": { + "$ref": "AAAAAAFfKudnG/biyzM=" + }, + "name": "data", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKufG4/jUFsY=", + "_parent": { + "$ref": "AAAAAAFfKudnG/biyzM=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Bool", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky0Ig1o8YU4s=", + "_parent": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky0KnCZAS+OA=", + "_parent": { + "$ref": "AAAAAAFky0Ig1o8YU4s=" + }, + "name": "options", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky0LqApDu034=", + "_parent": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "name": "updateIncrementalData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky0MM6pHoDKw=", + "_parent": { + "$ref": "AAAAAAFky0LqApDu034=" + }, + "name": "data", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky0MfopLELEY=", + "_parent": { + "$ref": "AAAAAAFky0LqApDu034=" + }, + "name": "finished", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFfKugU/PmNPJQ=", + "_parent": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "name": "incrementalDecodedImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKuhBpPo2Nvo=", + "_parent": { + "$ref": "AAAAAAFfKugU/PmNPJQ=" + }, + "name": "options", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKuiGTftezNo=", + "_parent": { + "$ref": "AAAAAAFfKugU/PmNPJQ=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UIImage", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFk7AwM/dC2p54=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageCacheKeyFilter", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7A02MdlCa2M=", + "_parent": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "source": { + "$ref": "AAAAAAFk7Aze6dcrc1c=" + }, + "target": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "visibility": "public" + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAFk73kBwjz+9fY=", + "_parent": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk73kBwjz/iCg=", + "_parent": { + "$ref": "AAAAAAFk73kBwjz+9fY=" + }, + "reference": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "none", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk73kBwj0A87w=", + "_parent": { + "$ref": "AAAAAAFk73kBwjz+9fY=" + }, + "reference": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "shared", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "visibility": "public", + "isDerived": false + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7AyMbdSMtVQ=", + "_parent": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "name": "cacheKey", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7AypTNWhPlU=", + "_parent": { + "$ref": "AAAAAAFk7AyMbdSMtVQ=" + }, + "name": "url", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7BAL/OfzEjc=", + "_parent": { + "$ref": "AAAAAAFk7AyMbdSMtVQ=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "String", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFk7A6KJuCHZbI=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageCacheSerializer", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7BDJZOsigsQ=", + "_parent": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "source": { + "$ref": "AAAAAAFk7BCTH+oZOBE=" + }, + "target": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "visibility": "public" + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAFk73j1izxh7DI=", + "_parent": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk73j1jDxidxA=", + "_parent": { + "$ref": "AAAAAAFk73j1izxh7DI=" + }, + "reference": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "none", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk73j1jDxjzus=", + "_parent": { + "$ref": "AAAAAAFk73j1izxh7DI=" + }, + "reference": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "shared", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "visibility": "public", + "isDerived": false + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7A8qouQCrJM=", + "_parent": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "name": "cacheData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7A85feUXlUs=", + "_parent": { + "$ref": "AAAAAAFk7A8qouQCrJM=" + }, + "name": "image", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7A9mAeYLke8=", + "_parent": { + "$ref": "AAAAAAFk7A8qouQCrJM=" + }, + "name": "data", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7A+i0+b/73A=", + "_parent": { + "$ref": "AAAAAAFk7A8qouQCrJM=" + }, + "name": "imageURL", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7BBRKOkkGYI=", + "_parent": { + "$ref": "AAAAAAFk7A8qouQCrJM=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Data", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFXmwdRJMUYGTs=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageDownloaderOperation", + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFky4EnyJoHXgk=", + "_parent": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky4FmmJsBK3E=", + "_parent": { + "$ref": "AAAAAAFky4EnyJoHXgk=" + }, + "name": "request", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky4JHRJ7YrhU=", + "_parent": { + "$ref": "AAAAAAFky4EnyJoHXgk=" + }, + "name": "session", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky4Jp1J+0Bdg=", + "_parent": { + "$ref": "AAAAAAFky4EnyJoHXgk=" + }, + "name": "options", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky4K/DqCQ6DE=", + "_parent": { + "$ref": "AAAAAAFky4EnyJoHXgk=" + }, + "name": "context", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky4L4L6FsOVg=", + "_parent": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "name": "addHandlers", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky4M4kKJmN1k=", + "_parent": { + "$ref": "AAAAAAFky4L4L6FsOVg=" + }, + "name": "progressBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky4NbSKNC3Tg=", + "_parent": { + "$ref": "AAAAAAFky4L4L6FsOVg=" + }, + "name": "completedBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky4PT6qQes1w=", + "_parent": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "name": "credential", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky4PsuqUYZjI=", + "_parent": { + "$ref": "AAAAAAFky4PT6qQes1w=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "URLCredential", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky4QsQ6YrSFU=", + "_parent": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "name": "setCredential", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky4RZfKclyYA=", + "_parent": { + "$ref": "AAAAAAFky4QsQ6YrSFU=" + }, + "name": "value", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky4SFRKgB5qs=", + "_parent": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "name": "cancel", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky4Svdaj7nf0=", + "_parent": { + "$ref": "AAAAAAFky4SFRKgB5qs=" + }, + "name": "token", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky4TM9qnXQuk=", + "_parent": { + "$ref": "AAAAAAFky4SFRKgB5qs=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Bool", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky4UEV6rqaoE=", + "_parent": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "name": "request", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky4U4wKw1It0=", + "_parent": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "name": "response", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky4VpKK2AUTU=", + "_parent": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "name": "dataTask", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky4WHga565mI=", + "_parent": { + "$ref": "AAAAAAFky4VpKK2AUTU=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "URLSessionTask", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFky49vaeVTiPQ=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageDownloaderRequestModifier", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAFk75A6HHm4W88=", + "_parent": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk75A6HHm5coU=", + "_parent": { + "$ref": "AAAAAAFk75A6HHm4W88=" + }, + "reference": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "none", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk75A6HHm6YP4=", + "_parent": { + "$ref": "AAAAAAFk75A6HHm4W88=" + }, + "reference": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "shared", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "visibility": "public", + "isDerived": false + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFky5N7SPLYdL0=", + "_parent": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "name": "modifiedRequest", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky5OhUfPSFJw=", + "_parent": { + "$ref": "AAAAAAFky5N7SPLYdL0=" + }, + "name": "request", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky5O8cfSuu80=", + "_parent": { + "$ref": "AAAAAAFky5N7SPLYdL0=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "URLRequest", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFk7D0m86FYiZQ=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageIndicator", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7D7FLq9KEOE=", + "_parent": { + "$ref": "AAAAAAFk7D0m86FYiZQ=" + }, + "source": { + "$ref": "AAAAAAFk7D56nKz+DL8=" + }, + "target": { + "$ref": "AAAAAAFk7D0m86FYiZQ=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7EAwILzXek0=", + "_parent": { + "$ref": "AAAAAAFk7D0m86FYiZQ=" + }, + "source": { + "$ref": "AAAAAAFk7D/fn7s6PNY=" + }, + "target": { + "$ref": "AAAAAAFk7D0m86FYiZQ=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7D1tOKNUQpw=", + "_parent": { + "$ref": "AAAAAAFk7D0m86FYiZQ=" + }, + "name": "indicatorView", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7D2NH6TnfK0=", + "_parent": { + "$ref": "AAAAAAFk7D0m86FYiZQ=" + }, + "name": "startAnimatingIndicator", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7D2jk6Z6puU=", + "_parent": { + "$ref": "AAAAAAFk7D0m86FYiZQ=" + }, + "name": "stopAnimatingIndicator", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7D25d6gNaKY=", + "_parent": { + "$ref": "AAAAAAFk7D0m86FYiZQ=" + }, + "name": "updateProgress", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFUkh5jeI3spbg=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageManagerDelegate", + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFUkh6LiI3wgxM=", + "_parent": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "name": "shouldDownloadImageForURL", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUkh65uI30vRk=", + "_parent": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "name": "shouldBlockFailedURL", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFUmNVIhta461s=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageOperation", + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmNWHXtbX7L0=", + "_parent": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "name": "cancel", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFUkhg5/4zs5zU=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImagePrefetcherDelegate", + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFUkht/NI1jZE4=", + "_parent": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "name": "didPrefetchURL:", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUkhu8u41n4Ps=", + "_parent": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "name": "didFinishWithTotalCount:", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLEnumeration", + "_id": "AAAAAAFUkiDjJo5QvT4=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageCacheType", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "literals": [ + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUkiD+ro5UDPI=", + "_parent": { + "$ref": "AAAAAAFUkiDjJo5QvT4=" + }, + "name": "SDImageCacheTypeNone", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUkiEOJo5YAWk=", + "_parent": { + "$ref": "AAAAAAFUkiDjJo5QvT4=" + }, + "name": "SDImageCacheTypeDisk", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUkiEUdY5bs1I=", + "_parent": { + "$ref": "AAAAAAFUkiDjJo5QvT4=" + }, + "name": "SDImageCacheTypeMemory", + "visibility": "public" + } + ] + }, + { + "_type": "UMLEnumeration", + "_id": "AAAAAAFk0MPrmZLdeGs=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageCacheOptions", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "literals": [ + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFk0MQrOpM/jI0=", + "_parent": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "name": "queryMemoryData", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFk0MRCXJO7Xl0=", + "_parent": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "name": "queryMemoryDataSync", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFk0MRaJJQ3LUY=", + "_parent": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "name": "queryDiskDataSync", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFk0MR51JSzxio=", + "_parent": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "name": "scaleDownLargeImages", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFk0MSZXZUvhjA=", + "_parent": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "name": "avoidDecodeImage", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFk0MS2hZWrSIM=", + "_parent": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "name": "decodeFirstFrameOnly", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFk0MTONZYnA3o=", + "_parent": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "name": "preloadAllFrames", + "visibility": "public" + } + ] + }, + { + "_type": "UMLEnumeration", + "_id": "AAAAAAFk7ATKAnkUjt4=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageCachesManagerOperationPolicy", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "literals": [ + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFk7AU1fnui68s=", + "_parent": { + "$ref": "AAAAAAFk7ATKAnkUjt4=" + }, + "name": "serial", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFk7AVOan0RTug=", + "_parent": { + "$ref": "AAAAAAFk7ATKAnkUjt4=" + }, + "name": "concurrent", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFk7AVno36AYek=", + "_parent": { + "$ref": "AAAAAAFk7ATKAnkUjt4=" + }, + "name": "highestOnly", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFk7AV+An/vm7g=", + "_parent": { + "$ref": "AAAAAAFk7ATKAnkUjt4=" + }, + "name": "lowestOnly", + "visibility": "public" + } + ] + }, + { + "_type": "UMLEnumeration", + "_id": "AAAAAAFkyzVnxm2Ab1g=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageCoderOptions", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "literals": [ + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFkyzXADnBSFdc=", + "_parent": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "name": "decodeFirstFrameOnly", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFkyzZGYHJ5+5E=", + "_parent": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "name": "decodeScaleFactor", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFkyzbTKndtAbI=", + "_parent": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "name": "encodeFirstFrameOnly", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFkyzbx8ni4xXQ=", + "_parent": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "name": "encodeCompressionQuality", + "visibility": "public" + } + ] + }, + { + "_type": "UMLEnumeration", + "_id": "AAAAAAFkyzlywn3Sx/Q=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageFormat", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "literals": [ + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFkyzm7rX6TNK0=", + "_parent": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "name": "underfined", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFkyzniln/T7fg=", + "_parent": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "name": "JPEG", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFkyzoDz4EeE/4=", + "_parent": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "name": "PNG", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFkyzoisIJpxLA=", + "_parent": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "name": "GIF", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFkyzo1F4O0qHE=", + "_parent": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "name": "TIFF", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFkyzpUIIT/rq0=", + "_parent": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "name": "WebP", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFkyzqLIIa3Chg=", + "_parent": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "name": "HEIC", + "visibility": "public" + } + ] + }, + { + "_type": "UMLEnumeration", + "_id": "AAAAAAFUmOC2fugTUX8=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageDownloaderOptions", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "literals": [ + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUmODurehEneQ=", + "_parent": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "name": "lowPriority", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUmOD23ehlAns=", + "_parent": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "name": "progressiveLoad", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUmOD+neiGg3g=", + "_parent": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "name": "useNSURLCache", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUmOEGbeinNtM=", + "_parent": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "name": "ignoreCachedResponse", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUmOENpujIT/I=", + "_parent": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "name": "continueInBackground", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUmOEVzujp/Q0=", + "_parent": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "name": "handleCookies", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUmOEc/ekKMBo=", + "_parent": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "name": "allowInvalidSSLCertificates", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUmOEkLekrSQE=", + "_parent": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "name": "highPriority", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFky2uhM1TIKQ4=", + "_parent": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "name": "scaleDownLargeImages", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFky2vJY1YTwQk=", + "_parent": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "name": "avoidDecodeImage", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFky2viY1deXps=", + "_parent": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "name": "decodeFirstFrameOnly", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFky2v7z1ipMKY=", + "_parent": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "name": "preloadAllFrames", + "visibility": "public" + } + ] + }, + { + "_type": "UMLEnumeration", + "_id": "AAAAAAFUkhyNUo23oFw=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageOptions", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "literals": [ + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUkhys4o27Ge0=", + "_parent": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "name": "retryFailed", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUkhza8o2/z9E=", + "_parent": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "name": "lowPriority", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUkhzs8o3Fkdk=", + "_parent": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "name": "progressiveLoad", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUkhz04o3ItAc=", + "_parent": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "name": "refreshCached", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUkhz84Y3L96A=", + "_parent": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "name": "continueInBackground", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUkh0C6Y3O214=", + "_parent": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "name": "handleCookies", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUkh2TUY3YpnQ=", + "_parent": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "name": "allowInvalidSSLCertificates", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUkh2bqY3bxlE=", + "_parent": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "name": "highPriority", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUkh2p4Y3e22E=", + "_parent": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "name": "delayPlaceholder", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUkh2x+Y3hQmw=", + "_parent": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "name": "transformAnimatedImage", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFUkh31iY3ox50=", + "_parent": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "name": "avoidAutoSetImage", + "visibility": "public" + }, + { + "_type": "UMLEnumerationLiteral", + "_id": "AAAAAAFkzPKuPGy7i4M=", + "_parent": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "name": "scaleDownLargeImages", + "visibility": "public" + } + ] + }, + { + "_type": "UMLPackage", + "_id": "AAAAAAFk7BauIRix5Go=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImage - Transformers", + "ownedElements": [ + { + "_type": "UMLClass", + "_id": "AAAAAAFk7BNlf/pTkyo=", + "_parent": { + "$ref": "AAAAAAFk7BauIRix5Go=" + }, + "name": "SDImagePipelineTransformer", + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7BQPCv5irlw=", + "_parent": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "name": "transformers", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Array ", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7BRdnQBKmBE=", + "_parent": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7BRzwgFf/6E=", + "_parent": { + "$ref": "AAAAAAFk7BRdnQBKmBE=" + }, + "name": "transformers", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7BbYDRkPcZw=", + "_parent": { + "$ref": "AAAAAAFk7BauIRix5Go=" + }, + "name": "SDImageRoundCornerTransformer", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7Bb86xmLb4E=", + "_parent": { + "$ref": "AAAAAAFk7BauIRix5Go=" + }, + "name": "SDImageResizingTransformer", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7Bce7hoHimk=", + "_parent": { + "$ref": "AAAAAAFk7BauIRix5Go=" + }, + "name": "SDImageCroppingTransformer", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFk7BHRjPCnfdg=", + "_parent": { + "$ref": "AAAAAAFk7BauIRix5Go=" + }, + "name": "SDImageTransformer", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7BOsyPu6CB8=", + "_parent": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "source": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "target": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7CKPEV9dRro=", + "_parent": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "source": { + "$ref": "AAAAAAFk7BbYDRkPcZw=" + }, + "target": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7CLPZWHITQ0=", + "_parent": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "source": { + "$ref": "AAAAAAFk7Bb86xmLb4E=" + }, + "target": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7CMBW2QVtcI=", + "_parent": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "source": { + "$ref": "AAAAAAFk7Bce7hoHimk=" + }, + "target": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7CMrm2ZiA3E=", + "_parent": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "source": { + "$ref": "AAAAAAFk7BhADB1EoQk=" + }, + "target": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7CNbqmhzvEA=", + "_parent": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "source": { + "$ref": "AAAAAAFk7Bhd7h3AKVk=" + }, + "target": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7CQo724NRzY=", + "_parent": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "source": { + "$ref": "AAAAAAFk7Bh7uh48Uvw=" + }, + "target": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7CRNf2/ipjs=", + "_parent": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "source": { + "$ref": "AAAAAAFk7Bicxh7WCxo=" + }, + "target": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk7CRttXGZGcg=", + "_parent": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "source": { + "$ref": "AAAAAAFk7Bi24B9S1R4=" + }, + "target": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visibility": "public" + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAFk73ggjzeamEo=", + "_parent": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk73ggjzebOxM=", + "_parent": { + "$ref": "AAAAAAFk73ggjzeamEo=" + }, + "reference": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "none", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk73ggjzec0ak=", + "_parent": { + "$ref": "AAAAAAFk73ggjzeamEo=" + }, + "reference": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "shared", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "visibility": "public", + "isDerived": false + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7BJFY/NyunQ=", + "_parent": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "name": "transformerKey", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7BJcdvSH9zc=", + "_parent": { + "$ref": "AAAAAAFk7BJFY/NyunQ=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "String", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7BKJjfW40dE=", + "_parent": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "name": "transformedImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7BKlz/bN5Ms=", + "_parent": { + "$ref": "AAAAAAFk7BKJjfW40dE=" + }, + "name": "image", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7BK3E/fBVsA=", + "_parent": { + "$ref": "AAAAAAFk7BKJjfW40dE=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7BLJGPi1v1s=", + "_parent": { + "$ref": "AAAAAAFk7BKJjfW40dE=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UIImage", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7BhADB1EoQk=", + "_parent": { + "$ref": "AAAAAAFk7BauIRix5Go=" + }, + "name": "SDImageFlippingTransformer", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7Bhd7h3AKVk=", + "_parent": { + "$ref": "AAAAAAFk7BauIRix5Go=" + }, + "name": "SDImageRotationTransformer", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7Bh7uh48Uvw=", + "_parent": { + "$ref": "AAAAAAFk7BauIRix5Go=" + }, + "name": "SDImageTintTransformer", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7Bicxh7WCxo=", + "_parent": { + "$ref": "AAAAAAFk7BauIRix5Go=" + }, + "name": "SDImageBlurTransformer", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7Bi24B9S1R4=", + "_parent": { + "$ref": "AAAAAAFk7BauIRix5Go=" + }, + "name": "SDImageFilterTransformer", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + } + ], + "visibility": "public" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFUmPjp9CtnN2Y=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "MKAnnotationView (WebCache)", + "ownedElements": [ + { + "_type": "UMLDependency", + "_id": "AAAAAAFk0RCPR6y62U8=", + "_parent": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "source": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "target": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmPndIiv0KoI=", + "_parent": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "name": "sd_setImageWithURL", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7C/5OzjRt0A=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDAnimatedImage", + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DOG2FbkH2w=", + "_parent": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "name": "animatedImageFormat", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFkyzlywn3Sx/Q=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DO4G1hTjI0=", + "_parent": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "name": "animatedImageData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Data", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DQVAVsOZyY=", + "_parent": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "name": "scale", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Float", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7DH2i0mDavU=", + "_parent": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7DIV1EqYqIk=", + "_parent": { + "$ref": "AAAAAAFk7DH2i0mDavU=" + }, + "name": "name", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7DImn0uM6LI=", + "_parent": { + "$ref": "AAAAAAFk7DH2i0mDavU=" + }, + "name": "bundle", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7DJZbE10mqg=", + "_parent": { + "$ref": "AAAAAAFk7DH2i0mDavU=" + }, + "name": "traitCollection", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7DKM7E6kOa0=", + "_parent": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7DKfeE+5qSU=", + "_parent": { + "$ref": "AAAAAAFk7DKM7E6kOa0=" + }, + "name": "path", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7DK+w1CtoF8=", + "_parent": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7DLSL1HCi5w=", + "_parent": { + "$ref": "AAAAAAFk7DK+w1CtoF8=" + }, + "name": "data", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7DLzaFLznpk=", + "_parent": { + "$ref": "AAAAAAFk7DK+w1CtoF8=" + }, + "name": "scale", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7DMSCVPnFmw=", + "_parent": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7DMimlT8b9Y=", + "_parent": { + "$ref": "AAAAAAFk7DMSCVPnFmw=" + }, + "name": "animatedCoder", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7DM/Y1XwZRg=", + "_parent": { + "$ref": "AAAAAAFk7DMSCVPnFmw=" + }, + "name": "scale", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7DVduGJDDTw=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDAnimatedImageView", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAFk7DwdIJcO1bc=", + "_parent": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk7DwdIJcP5mg=", + "_parent": { + "$ref": "AAAAAAFk7DwdIJcO1bc=" + }, + "reference": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "none", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk7DwdIZcQYP4=", + "_parent": { + "$ref": "AAAAAAFk7DwdIJcO1bc=" + }, + "reference": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "shared", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "visibility": "public", + "isDerived": false + } + ], + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DaZpG13UcQ=", + "_parent": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "name": "currentFrame", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DbG6G9fPWY=", + "_parent": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "name": "currentFrameIndex", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DbkTXDOHZI=", + "_parent": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "name": "currentLoopCount", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DcDmHI9EDE=", + "_parent": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "name": "shouldCustomLoopCount", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7Dc1vHR/unM=", + "_parent": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "name": "animationRepeatCount", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DdOkHXuWe8=", + "_parent": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "name": "maxBufferSize", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DdpU3dd33Y=", + "_parent": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "name": "shouldIncrementalLoad", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DeCxXjMVds=", + "_parent": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "name": "runLoopMode", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7CZN3IZtF9w=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDAnimatedImageView (WebCache)", + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7CbOtYiUask=", + "_parent": { + "$ref": "AAAAAAFk7CZN3IZtF9w=" + }, + "name": "sd_setImageWithURL", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk0Oy3g5480kU=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDDiskCache", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFky08wi8R0DcY=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageAPNGCoder", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk74JHz1jQLXI=", + "_parent": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "source": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "target": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFUkh79WI34fB0=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageCache", + "ownedElements": [ + { + "_type": "UMLDependency", + "_id": "AAAAAAFfKuwBKAhI5QU=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "source": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "target": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "visibility": "public" + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAFk74e4zmN2kbM=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "source": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "target": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUkiFzJY5gThM=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "sharedImageCache", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk0LaA7lthFIA=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "config", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmPDC7hpSvPQ=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "diskCachePath", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmPDhrRsNyCc=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "additionalCachePathBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmPHYnB7PNs4=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFUmPHujB9dtv8=", + "_parent": { + "$ref": "AAAAAAFUmPHYnB7PNs4=" + }, + "name": "namespace", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFUmPH10x+6tbo=", + "_parent": { + "$ref": "AAAAAAFUmPHYnB7PNs4=" + }, + "name": "diskCacheDirectory", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0M0rV9jBMCc=", + "_parent": { + "$ref": "AAAAAAFUmPHYnB7PNs4=" + }, + "name": "config", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmPTT0CgBzK8=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "cachePath", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0M4S8twW5+U=", + "_parent": { + "$ref": "AAAAAAFUmPTT0CgBzK8=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmPMOWiHsOa0=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "store", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0M5vnd2D2UU=", + "_parent": { + "$ref": "AAAAAAFUmPMOWiHsOa0=" + }, + "name": "image", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0M+LYOHqRK0=", + "_parent": { + "$ref": "AAAAAAFUmPMOWiHsOa0=" + }, + "name": "imageData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0M6EfN53lZA=", + "_parent": { + "$ref": "AAAAAAFUmPMOWiHsOa0=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0M7sfuBfXtM=", + "_parent": { + "$ref": "AAAAAAFUmPMOWiHsOa0=" + }, + "name": "toDisk", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0M6YlN9rMuM=", + "_parent": { + "$ref": "AAAAAAFUmPMOWiHsOa0=" + }, + "name": "completionBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmPMtQiKnVfM=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "storeImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NA14uSITyw=", + "_parent": { + "$ref": "AAAAAAFUmPMtQiKnVfM=" + }, + "name": "image", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NBKg+V809s=", + "_parent": { + "$ref": "AAAAAAFUmPMtQiKnVfM=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0NC0bOZw4VQ=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "storeImageData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NDn5ekwA60=", + "_parent": { + "$ref": "AAAAAAFk0NC0bOZw4VQ=" + }, + "name": "imageData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0ND8FeokQ2o=", + "_parent": { + "$ref": "AAAAAAFk0NC0bOZw4VQ=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0NF3Z+sY0tc=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "diskImageExists", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NHMQe7MuvA=", + "_parent": { + "$ref": "AAAAAAFk0NF3Z+sY0tc=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NG4aO3YPoU=", + "_parent": { + "$ref": "AAAAAAFk0NF3Z+sY0tc=" + }, + "name": "completionBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0NJKG+/90EA=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "diskImageDataExists", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NJxbPM37AM=", + "_parent": { + "$ref": "AAAAAAFk0NJKG+/90EA=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NKQ2/QrKBw=", + "_parent": { + "$ref": "AAAAAAFk0NJKG+/90EA=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Bool", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0NLcpfVc3Q8=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "diskImageData", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NMCDvgci8E=", + "_parent": { + "$ref": "AAAAAAFk0NLcpfVc3Q8=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NMeBvkQN4g=", + "_parent": { + "$ref": "AAAAAAFk0NLcpfVc3Q8=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Data", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0NOWwPpBKis=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "queryCacheOperation", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NPBYPtWv+Q=", + "_parent": { + "$ref": "AAAAAAFk0NOWwPpBKis=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NSsewB07tQ=", + "_parent": { + "$ref": "AAAAAAFk0NOWwPpBKis=" + }, + "name": "options", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NT6LQLWd/w=", + "_parent": { + "$ref": "AAAAAAFk0NOWwPpBKis=" + }, + "name": "context", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NPa8fxK5qM=", + "_parent": { + "$ref": "AAAAAAFk0NOWwPpBKis=" + }, + "name": "doneBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NQUQv0+Nrc=", + "_parent": { + "$ref": "AAAAAAFk0NOWwPpBKis=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFUmOxnEwduTCw=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmPOk0iRaSME=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "imageFromMemoryCache", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NW0sQXuat4=", + "_parent": { + "$ref": "AAAAAAFUmPOk0iRaSME=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NXOaQbiOVE=", + "_parent": { + "$ref": "AAAAAAFUmPOk0iRaSME=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UIImage", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmPPBiSUVHSU=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "imageFromDiskCache", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NYXigiM/xU=", + "_parent": { + "$ref": "AAAAAAFUmPPBiSUVHSU=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NYsKgmA5ek=", + "_parent": { + "$ref": "AAAAAAFUmPPBiSUVHSU=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UIImage", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0NaQzAru2sk=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "imageFromCache", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NayRAz3iMU=", + "_parent": { + "$ref": "AAAAAAFk0NaQzAru2sk=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NbLtA3rpzg=", + "_parent": { + "$ref": "AAAAAAFk0NaQzAru2sk=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UIImage", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmPPiwSXQs7U=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "removeImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0Ncfzg+VKFY=", + "_parent": { + "$ref": "AAAAAAFUmPPiwSXQs7U=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NdVRxCJTiA=", + "_parent": { + "$ref": "AAAAAAFUmPPiwSXQs7U=" + }, + "name": "fromDisk", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NdupxF9aYQ=", + "_parent": { + "$ref": "AAAAAAFUmPPiwSXQs7U=" + }, + "name": "completion", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0NfB0BJxwa0=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "removeImageFromMemory", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NfbGBOGo44=", + "_parent": { + "$ref": "AAAAAAFk0NfB0BJxwa0=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0NhSwxdz+po=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "removeImageFromDisk", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0Nh38xiIUTM=", + "_parent": { + "$ref": "AAAAAAFk0NhSwxdz+po=" + }, + "name": "key", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmPQzYSaLCQc=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "clearMemory", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmPRYYSdGCZA=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "clearDIsk", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0Ni6jBqNVSo=", + "_parent": { + "$ref": "AAAAAAFUmPRYYSdGCZA=" + }, + "name": "completion", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmPT4WSi8pg0=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "deleteOldFiles", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NkNXRv6Pho=", + "_parent": { + "$ref": "AAAAAAFUmPT4WSi8pg0=" + }, + "name": "completionBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0Nk9Zhzuux0=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "getSize", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NlfoB4DAsY=", + "_parent": { + "$ref": "AAAAAAFk0Nk9Zhzuux0=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UInt", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0NmTbx80+MQ=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "getDiskCount", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NmtcSBJUHQ=", + "_parent": { + "$ref": "AAAAAAFk0NmTbx80+MQ=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UInt", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk0Nn28SF6Hq4=", + "_parent": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "name": "calculateSize", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk0NoSYiKPUdA=", + "_parent": { + "$ref": "AAAAAAFk0Nn28SF6Hq4=" + }, + "name": "completionBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFXmwGn6ZeqpYw=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageCacheConfig", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAFXmwYAOLO3R8M=", + "_parent": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFXmwYAOLO4X9g=", + "_parent": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "reference": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "none", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFXmwYAOLO5TNo=", + "_parent": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "reference": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "shared", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "visibility": "public", + "isDerived": false + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAFk74cA82HEn7s=", + "_parent": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk74cA82HFdlQ=", + "_parent": { + "$ref": "AAAAAAFk74cA82HEn7s=" + }, + "reference": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "none", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk74cA82HGTl0=", + "_parent": { + "$ref": "AAAAAAFk74cA82HEn7s=" + }, + "reference": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "shared", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "visibility": "public", + "isDerived": false + } + ], + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmPBKVhghKWk=", + "_parent": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "name": "shouldDecompressImages", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmPBxrhjcaQc=", + "_parent": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "name": "shouldDisableiCloud", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmPCLlRmXEPs=", + "_parent": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "name": "shouldCacheImagesInMemory", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmPD+pRvI9sU=", + "_parent": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "name": "maxCacheAge", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmPEdRRyDmKo=", + "_parent": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "name": "maxCacheSize", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7AHuD1yFB/0=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageCachesManager", + "ownedElements": [ + { + "_type": "UMLDependency", + "_id": "AAAAAAFk74icCGYuXpY=", + "_parent": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "source": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "target": { + "$ref": "AAAAAAFk7ATKAnkUjt4=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7ALOcGXu/S8=", + "_parent": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "name": "sharedManager", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7AOZr28Bcso=", + "_parent": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "name": "caches", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Array ", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7AMCg2fWSP0=", + "_parent": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "name": "queryOperationPolicy", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7AMe/WlFG7c=", + "_parent": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "name": "storeOperationPolicy", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7ANGZ2q0x2Q=", + "_parent": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "name": "removeOperationPolicy", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7ANfz2wjKJg=", + "_parent": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "name": "containsOperationPolicy", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7AN7JG2S4JE=", + "_parent": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "name": "clearOperationPolicy", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7AQw/nZyZkk=", + "_parent": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "name": "addCache", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7ARL1nfhIfg=", + "_parent": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "name": "removeCache", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFky1HOFNP2U1I=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageCoderHelper", + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFky1HlrdRLhc8=", + "_parent": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "name": "animatedImage", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1IcbtSgjNk=", + "_parent": { + "$ref": "AAAAAAFky1HlrdRLhc8=" + }, + "name": "frames", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1IztdUQJwY=", + "_parent": { + "$ref": "AAAAAAFky1HlrdRLhc8=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UIImage", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky1MmItpS0IE=", + "_parent": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "name": "frames", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1NUq9u5LK4=", + "_parent": { + "$ref": "AAAAAAFky1MmItpS0IE=" + }, + "name": "animatedImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1OHY9yVU2c=", + "_parent": { + "$ref": "AAAAAAFky1MmItpS0IE=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Array ", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky1Qmzd9zXiU=", + "_parent": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "name": "colorSpaceGetDeviceRGB", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1RTpuDahlk=", + "_parent": { + "$ref": "AAAAAAFky1Qmzd9zXiU=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "CGColorSpace", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky1S1OuHtMmU=", + "_parent": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "name": "cgImageContainsAlpha", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1TUQONUmdw=", + "_parent": { + "$ref": "AAAAAAFky1S1OuHtMmU=" + }, + "name": "cgImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1UDYeQwgHQ=", + "_parent": { + "$ref": "AAAAAAFky1S1OuHtMmU=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Bool", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky1WnxOVDz7I=", + "_parent": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "name": "cgImageCreateDecoded", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1XBBOaq/0g=", + "_parent": { + "$ref": "AAAAAAFky1WnxOVDz7I=" + }, + "name": "cgImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1X3zOeGYnM=", + "_parent": { + "$ref": "AAAAAAFky1WnxOVDz7I=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "CGImage", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky1Zx3+iZ+Sc=", + "_parent": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "name": "cgImageCreateDecoded", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1aS3+oA4pE=", + "_parent": { + "$ref": "AAAAAAFky1Zx3+iZ+Sc=" + }, + "name": "cgImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1bBaOrco+Q=", + "_parent": { + "$ref": "AAAAAAFky1Zx3+iZ+Sc=" + }, + "name": "orientation", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1beF+u4Fkw=", + "_parent": { + "$ref": "AAAAAAFky1Zx3+iZ+Sc=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "CGImage", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky1comezL+vc=", + "_parent": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "name": "decodedImage", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1dVUu4yTRU=", + "_parent": { + "$ref": "AAAAAAFky1comezL+vc=" + }, + "name": "image", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1dpo+8OP7A=", + "_parent": { + "$ref": "AAAAAAFky1comezL+vc=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UIImage", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky1ei5PAhNRU=", + "_parent": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "name": "decodedAndScaledDownImage", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1fQA/GIbME=", + "_parent": { + "$ref": "AAAAAAFky1ei5PAhNRU=" + }, + "name": "image", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1fhHfJkp70=", + "_parent": { + "$ref": "AAAAAAFky1ei5PAhNRU=" + }, + "name": "limitBytes", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1f5FfNAEAs=", + "_parent": { + "$ref": "AAAAAAFky1ei5PAhNRU=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UIImage", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky1gyjvRTopk=", + "_parent": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "name": "imageOrientation", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1hqFfW6xOQ=", + "_parent": { + "$ref": "AAAAAAFky1gyjvRTopk=" + }, + "name": "exifOrientation", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1iMD/aWPZA=", + "_parent": { + "$ref": "AAAAAAFky1gyjvRTopk=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "UIImageOrientation", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky1jM4Pep+/8=", + "_parent": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "name": "exifOrientation", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1jnf/kQtIY=", + "_parent": { + "$ref": "AAAAAAFky1jM4Pep+/8=" + }, + "name": "imageOrientation", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1k25fnsBPQ=", + "_parent": { + "$ref": "AAAAAAFky1jM4Pep+/8=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "CGImagePropertyOrientation", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFfKukEJfyENXE=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageCodersManager", + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFfKvIMwCceZuI=", + "_parent": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "name": "sharedInstance", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFfKvJtjym0wQE=", + "_parent": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "name": "coders", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Array ", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFfKvJK9yjW40I=", + "_parent": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "name": "add", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKvOdWTJKxZs=", + "_parent": { + "$ref": "AAAAAAFfKvJK9yjW40I=" + }, + "name": "coder", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFfKvPFeTMmARs=", + "_parent": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "name": "remove", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFfKvPZ+TQg+cs=", + "_parent": { + "$ref": "AAAAAAFfKvPFeTMmARs=" + }, + "name": "coder", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFky1A/vstXuLs=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageFrame", + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky1B7UMw/+L4=", + "_parent": { + "$ref": "AAAAAAFky1A/vstXuLs=" + }, + "name": "image", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky1CcsM2KQ34=", + "_parent": { + "$ref": "AAAAAAFky1A/vstXuLs=" + }, + "name": "duration", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFky1DNOM7VKvU=", + "_parent": { + "$ref": "AAAAAAFky1A/vstXuLs=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1DfKc/PBwY=", + "_parent": { + "$ref": "AAAAAAFky1DNOM7VKvU=" + }, + "name": "image", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky1ENUtCrexU=", + "_parent": { + "$ref": "AAAAAAFky1DNOM7VKvU=" + }, + "name": "duration", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFfKumijf36cE8=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageGIFCoder", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk74ISXli+i9k=", + "_parent": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "source": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "target": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFfKul3rf0/okM=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageIOCoder", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFkzOBPBONMct8=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageLoadersManager", + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFkzOIg/+78rRg=", + "_parent": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "name": "sharedManager", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFkzOOPjva3FJM=", + "_parent": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "name": "loaders", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "Array ", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFkzOP6yPhv64w=", + "_parent": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "name": "addLoader", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFkzOQxGfm6yKY=", + "_parent": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "name": "removeLoader", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFfKunO1f612hU=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDImageWebPCoder", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk74Du0lUy4R4=", + "_parent": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "source": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "target": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk74ElK1VEr6I=", + "_parent": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "source": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "target": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk0Oaeq24jZhk=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDMemoryCache", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk74n+b2zyIZQ=", + "_parent": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "source": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "target": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7D56nKz+DL8=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageActivityIndicator", + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7D9GQLKXmoI=", + "_parent": { + "$ref": "AAAAAAFk7D56nKz+DL8=" + }, + "name": "gray", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7D9ma7Sv4PA=", + "_parent": { + "$ref": "AAAAAAFk7D56nKz+DL8=" + }, + "name": "grayLarge", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7D+E67bH8oY=", + "_parent": { + "$ref": "AAAAAAFk7D56nKz+DL8=" + }, + "name": "white", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7D+YK7jfdL0=", + "_parent": { + "$ref": "AAAAAAFk7D56nKz+DL8=" + }, + "name": "whiteLarge", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7Aze6dcrc1c=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageCacheKeyFilter", + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7A2zWNuPpjU=", + "_parent": { + "$ref": "AAAAAAFk7Aze6dcrc1c=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7A3L6Nykt8g=", + "_parent": { + "$ref": "AAAAAAFk7A2zWNuPpjU=" + }, + "name": "block", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7BCTH+oZOBE=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageCacheSerializer", + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFk7BE9ae7ahlI=", + "_parent": { + "$ref": "AAAAAAFk7BCTH+oZOBE=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFk7BFdAe/v8BA=", + "_parent": { + "$ref": "AAAAAAFk7BE9ae7ahlI=" + }, + "name": "block", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFUmN6ZSOUCaRM=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageCombinedOperation", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFUmN83duYfrao=", + "_parent": { + "$ref": "AAAAAAFUmN6ZSOUCaRM=" + }, + "source": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "target": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky13cFAMXBnI=", + "_parent": { + "$ref": "AAAAAAFUmN6ZSOUCaRM=" + }, + "name": "cacheOperation", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky14VtQRiZl8=", + "_parent": { + "$ref": "AAAAAAFUmN6ZSOUCaRM=" + }, + "name": "loaderOperation", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFUkh8UMI38gtY=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageDownloader", + "ownedElements": [ + { + "_type": "UMLDependency", + "_id": "AAAAAAFUmOrfAwPdh8M=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "source": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "target": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "visibility": "public" + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAFfKuxM+AnptLY=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "source": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "target": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "visibility": "public" + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAFk75NrQ3+1ToE=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "source": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "target": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "visibility": "public" + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAFk75N4Y3/bXkw=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "source": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "target": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUkiJAhI5kL78=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "name": "sharedDownloader", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmOMr1ewzvaI=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "name": "config", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmONDtOzuN2c=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "name": "requestModifier", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmOaPcvo7CuM=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "name": "sessionConfiguration", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmOa7+/r2ysU=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "name": "suspended", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmOiCz/5aGv0=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "name": "currentDownloadCount", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFXmuCdynfN50Y=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFXmuEYDHj2f9E=", + "_parent": { + "$ref": "AAAAAAFXmuCdynfN50Y=" + }, + "name": "config", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmOeh6PwLtkk=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "name": "setValue", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky3bGFoPQ/LU=", + "_parent": { + "$ref": "AAAAAAFUmOeh6PwLtkk=" + }, + "name": "value", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky3bmjoSsVXs=", + "_parent": { + "$ref": "AAAAAAFUmOeh6PwLtkk=" + }, + "name": "HTTPHeaderField", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFky3dFIIXZ21M=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "name": "value", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky3eIKofmc/s=", + "_parent": { + "$ref": "AAAAAAFky3dFIIXZ21M=" + }, + "name": "HTTPHeaderField", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky3eiCYjC/E8=", + "_parent": { + "$ref": "AAAAAAFky3dFIIXZ21M=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "String", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmOOite2pkfo=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "name": "downloadImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFXmuK8y3sdotY=", + "_parent": { + "$ref": "AAAAAAFUmOOite2pkfo=" + }, + "name": "url", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFXmuLgMHuZcI8=", + "_parent": { + "$ref": "AAAAAAFUmOOite2pkfo=" + }, + "name": "options", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky3iSHotTP4Y=", + "_parent": { + "$ref": "AAAAAAFUmOOite2pkfo=" + }, + "name": "context", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFXmuMLQXwVkMM=", + "_parent": { + "$ref": "AAAAAAFUmOOite2pkfo=" + }, + "name": "progressBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFXmuM7iXyR7gc=", + "_parent": { + "$ref": "AAAAAAFUmOOite2pkfo=" + }, + "name": "completedBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFUmOW7A/c+Z/0=", + "_parent": { + "$ref": "AAAAAAFUmOOite2pkfo=" + }, + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "DownloadToken", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmOgcH/2BRjw=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "name": "cancelAllDownloads", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmOZtsvmAcFQ=", + "_parent": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "name": "invalidateSessionAndCancel", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFky4wTy8jjfCc=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageDownloaderConfig", + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky4zOJs9aW9c=", + "_parent": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "name": "default", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky4z9vtF/kCc=", + "_parent": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "name": "maxConcurrentDownloads", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky40X5tLK/zc=", + "_parent": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "name": "downloadTimeout", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky400JdQVn+Q=", + "_parent": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "name": "sessionConfiguration", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky41Rt9Vg34c=", + "_parent": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "name": "operationClass", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky419KNarbXU=", + "_parent": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "name": "executionOrder", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky42Z0df2Ke8=", + "_parent": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "name": "urlCredential", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky424lNlB4TI=", + "_parent": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "name": "username", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky43MudqMI9E=", + "_parent": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "name": "password", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFky5XHEfWLtyM=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageDownloaderRequestModifier", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk75BsT3pTLSM=", + "_parent": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "source": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "target": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFky5ZuM/uFU/4=", + "_parent": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky5a1Jfx/OCA=", + "_parent": { + "$ref": "AAAAAAFky5ZuM/uFU/4=" + }, + "name": "block", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFUkiR/Go5pUW0=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageDownloaderOperation", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFUmORm3fAwE60=", + "_parent": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "source": { + "$ref": "AAAAAAFk0Oy3g5480kU=" + }, + "target": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "visibility": "public" + }, + { + "_type": "UMLGeneralization", + "_id": "AAAAAAFUmOy6gwh7Mto=", + "_parent": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "source": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "target": { + "$ref": "AAAAAAFUmOxnEwduTCw=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk75KzQn7NZvE=", + "_parent": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "source": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "target": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk75MKYn8SsQ8=", + "_parent": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "source": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "target": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmO2TmQzzs/g=", + "_parent": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "name": "options", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky4mAub8FNII=", + "_parent": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "name": "context", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFXmuJtT3q/PXo=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageDownloadToken", + "ownedElements": [ + { + "_type": "UMLDependency", + "_id": "AAAAAAFXmuZ1booW7c8=", + "_parent": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "source": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "target": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "visibility": "public" + }, + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk75MgOn8+VeA=", + "_parent": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "source": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "target": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFXmuY4yIivPbY=", + "_parent": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "name": "url", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFXmuZPjolqbRg=", + "_parent": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "name": "request", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky24wtWMHKQ0=", + "_parent": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "name": "response", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFUkhwuq42z3w4=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageManager", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAFUmNGSiNAIwc4=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFUmNGSiNAJw9E=", + "_parent": { + "$ref": "AAAAAAFUmNGSiNAIwc4=" + }, + "reference": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "none", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFUmNGSiNAKXzo=", + "_parent": { + "$ref": "AAAAAAFUmNGSiNAIwc4=" + }, + "reference": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "shared", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "visibility": "public", + "isDerived": false + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAFk6+vKjo5YRUw=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "source": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "target": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "visibility": "public" + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAFUmNjw298aBP0=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFUmNjw298bVKc=", + "_parent": { + "$ref": "AAAAAAFUmNjw298aBP0=" + }, + "reference": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "none", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFUmNjw298cZas=", + "_parent": { + "$ref": "AAAAAAFUmNjw298aBP0=" + }, + "reference": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "shared", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "visibility": "public", + "isDerived": false + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAFk73GNVxfQMts=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk73GNVxfRKkM=", + "_parent": { + "$ref": "AAAAAAFk73GNVxfQMts=" + }, + "reference": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "none", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFk73GNVxfSppE=", + "_parent": { + "$ref": "AAAAAAFk73GNVxfQMts=" + }, + "reference": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "shared", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "visibility": "public", + "isDerived": false + } + ], + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUkiBj3o4EzZs=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "name": "sharedManager", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky2HbvA+NZl4=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "name": "delegate", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky2J/rxG0jPU=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "name": "imageCache", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky2KxrxL/YZE=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "name": "imageLoader", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky2Ld4BRKPO4=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "name": "transformer", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky2MdORXm73I=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "name": "cacheKeyFilter", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky2NDyRcxc0E=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "name": "cacheSerializer", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky2OkAhh8hEE=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "name": "running", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky2PUsxnHAYw=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "name": "defaultImageCache", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFky2P6zBsSQ7s=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "name": "defaultImageLoader", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFky2Q6HRxddGo=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "name": "init", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky2SR9h6hIkY=", + "_parent": { + "$ref": "AAAAAAFky2Q6HRxddGo=" + }, + "name": "cache", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky2TBtx99rws=", + "_parent": { + "$ref": "AAAAAAFky2Q6HRxddGo=" + }, + "name": "loader", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUkh/xZ44AqYk=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "name": "loadImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFUmNYJLthMwcI=", + "_parent": { + "$ref": "AAAAAAFUkh/xZ44AqYk=" + }, + "name": "url", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky2Y2hi/Lzsk=", + "_parent": { + "$ref": "AAAAAAFUkh/xZ44AqYk=" + }, + "name": "options", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky2ggvTtHn8g=", + "_parent": { + "$ref": "AAAAAAFUkh/xZ44AqYk=" + }, + "name": "context", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky2buoDGCF2M=", + "_parent": { + "$ref": "AAAAAAFUkh/xZ44AqYk=" + }, + "name": "progressBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky2cU+DJew2M=", + "_parent": { + "$ref": "AAAAAAFUkh/xZ44AqYk=" + }, + "name": "completedBlock", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFky2dKEjM6o0s=", + "_parent": { + "$ref": "AAAAAAFUkh/xZ44AqYk=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "CombinedOperatiom", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmNLtYNLc08o=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "name": "cancelAll", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmNORx9Q1mi4=", + "_parent": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "name": "cacheKey", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAFky2kWkT8m0Eo=", + "_parent": { + "$ref": "AAAAAAFUmNORx9Q1mi4=" + }, + "name": "url", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "in" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAFUmNbDrdlJMIU=", + "_parent": { + "$ref": "AAAAAAFUmNORx9Q1mi4=" + }, + "name": "Parameter1", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "String", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "direction": "return" + } + ], + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFUkhgItozoKPM=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImagePrefetcher", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAFUmMzgZcn8MSQ=", + "_parent": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFUmMzgZsn92Qw=", + "_parent": { + "$ref": "AAAAAAFUmMzgZcn8MSQ=" + }, + "reference": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "none", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFUmMzgZsn+nz8=", + "_parent": { + "$ref": "AAAAAAFUmMzgZcn8MSQ=" + }, + "reference": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "shared", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "visibility": "public", + "isDerived": true + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAFUmM8TqsupT40=", + "_parent": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFUmM8Tqsuqc7A=", + "_parent": { + "$ref": "AAAAAAFUmM8TqsupT40=" + }, + "reference": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "none", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAFUmM8Tqsuru94=", + "_parent": { + "$ref": "AAAAAAFUmM8TqsupT40=" + }, + "reference": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "visibility": "public", + "navigable": true, + "aggregation": "shared", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "isID": false + }, + "visibility": "public", + "isDerived": false + } + ], + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmM4zy8syqFU=", + "_parent": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "name": "sharedImagePrefetcher", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk0LGPQUYY/Mk=", + "_parent": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "name": "delegate", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFUmMwm7Mnxz9U=", + "_parent": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "name": "options", + "stereotype": "", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmM3dVsr1bHY=", + "_parent": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "name": "prefetchURLs:", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmNCMgs5kwbc=", + "_parent": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "name": "cancelPrefetching", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7D/fn7s6PNY=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageProgressIndicator", + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7ECrIb9dr0E=", + "_parent": { + "$ref": "AAAAAAFk7D/fn7s6PNY=" + }, + "name": "default", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7EDL38F1+hA=", + "_parent": { + "$ref": "AAAAAAFk7D/fn7s6PNY=" + }, + "name": "bar", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7DiDGnn/fLM=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "SDWebImageTransition", + "visibility": "public", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DkRAnpj0zo=", + "_parent": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "name": "avoidAutoSetImage", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7Dk9kHu9TbQ=", + "_parent": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "name": "duration", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DlVhH0silI=", + "_parent": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "name": "animationOptions", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DlyIH6bXfc=", + "_parent": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "name": "prepares", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DmQ2IAKsT8=", + "_parent": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "name": "animations", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DmwIoF5RvY=", + "_parent": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "name": "completion", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DoQgYLooEE=", + "_parent": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "name": "fade", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DoyvITQMB4=", + "_parent": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "name": "flipFromLeft", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DpQW4a4gGQ=", + "_parent": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "name": "flipFromRight", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DqAhYigq5c=", + "_parent": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "name": "flipFromTop", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DqhWYqIfdY=", + "_parent": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "name": "flipFromBottom", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7DrIaoxwRsk=", + "_parent": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "name": "curlUp", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAFk7Drq/45YO1k=", + "_parent": { + "$ref": "AAAAAAFk7DiDGnn/fLM=" + }, + "name": "curlDown", + "visibility": "public", + "isStatic": true, + "isLeaf": false, + "type": "", + "isReadOnly": false, + "isOrdered": false, + "isUnique": false, + "isDerived": false, + "aggregation": "none", + "isID": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFUmPoFSiy4ZTk=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "UIButton (WebCache)", + "ownedElements": [ + { + "_type": "UMLDependency", + "_id": "AAAAAAFk0Q/6pKhroeQ=", + "_parent": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "source": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "target": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmPsYkS1rEno=", + "_parent": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "name": "sd_setImageWithURL", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFXmnErIidawX8=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "UIImageView (HighlightedWebCache)", + "ownedElements": [ + { + "_type": "UMLDependency", + "_id": "AAAAAAFk0Q9x+qJrGM4=", + "_parent": { + "$ref": "AAAAAAFXmnErIidawX8=" + }, + "source": { + "$ref": "AAAAAAFXmnErIidawX8=" + }, + "target": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFXmnErIideM/I=", + "_parent": { + "$ref": "AAAAAAFXmnErIidawX8=" + }, + "name": "sd_setHighlightedImageWithURL", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFUmPtmMC6BqlU=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "UIImageView (WebCache)", + "ownedElements": [ + { + "_type": "UMLDependency", + "_id": "AAAAAAFk0Q5c9Jg/0Jc=", + "_parent": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "source": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "target": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFUmPuK4C6yWrI=", + "_parent": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "name": "sd_setImageWithURL", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFXmsqK3SdrXmw=", + "_parent": { + "$ref": "AAAAAAFUkhbx4ozg49g=" + }, + "name": "UIView (WebCache)", + "ownedElements": [ + { + "_type": "UMLDependency", + "_id": "AAAAAAFk0RH/JbQKgpI=", + "_parent": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "source": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "target": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "visibility": "public" + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAFk0RKU97ifqxY=", + "_parent": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "source": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "target": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "visibility": "public" + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAFk7CeGFosTNLw=", + "_parent": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "source": { + "$ref": "AAAAAAFk7CZN3IZtF9w=" + }, + "target": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAFXmsqK3idvzv0=", + "_parent": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "name": "sd_internalSetImageWithURL", + "visibility": "public", + "isStatic": false, + "isLeaf": false, + "concurrency": "sequential", + "isQuery": false, + "isAbstract": false + } + ], + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + } + ], + "visibility": "public" + }, + { + "_type": "UMLPackage", + "_id": "AAAAAAFUkhchsIzka3U=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "WebP", + "visibility": "public" + }, + { + "_type": "UMLPackage", + "_id": "AAAAAAFUmOwkzAc9obg=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Foundation", + "ownedElements": [ + { + "_type": "UMLClass", + "_id": "AAAAAAFk0ObxVHApLxs=", + "_parent": { + "$ref": "AAAAAAFUmOwkzAc9obg=" + }, + "name": "NSCache", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFUmOxnEwduTCw=", + "_parent": { + "$ref": "AAAAAAFUmOwkzAc9obg=" + }, + "name": "NSOperation", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFky4ZtTLIlNBo=", + "_parent": { + "$ref": "AAAAAAFUmOwkzAc9obg=" + }, + "name": "NSURLSessionDataDelegate", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAFky4ZDu7Eiw8Y=", + "_parent": { + "$ref": "AAAAAAFUmOwkzAc9obg=" + }, + "name": "NSURLSessionTaskDelegate", + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false + } + ], + "visibility": "public" + }, + { + "_type": "UMLPackage", + "_id": "AAAAAAFk7DEC6kIXiU0=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "UIKit", + "ownedElements": [ + { + "_type": "UMLClass", + "_id": "AAAAAAFk7DEaV0J1rfc=", + "_parent": { + "$ref": "AAAAAAFk7DEC6kIXiU0=" + }, + "name": "UIImage", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAFk7DFeUkRjApo=", + "_parent": { + "$ref": "AAAAAAFk7DEaV0J1rfc=" + }, + "source": { + "$ref": "AAAAAAFk7C/5OzjRt0A=" + }, + "target": { + "$ref": "AAAAAAFk7DEaV0J1rfc=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk7DWl62Lbshc=", + "_parent": { + "$ref": "AAAAAAFk7DEC6kIXiU0=" + }, + "name": "UIImageView", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAFk7DZYV2rPuLs=", + "_parent": { + "$ref": "AAAAAAFk7DWl62Lbshc=" + }, + "source": { + "$ref": "AAAAAAFk7DVduGJDDTw=" + }, + "target": { + "$ref": "AAAAAAFk7DWl62Lbshc=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + } + ], + "visibility": "public" + }, + { + "_type": "UMLClassDiagram", + "_id": "AAAAAAFk72gtuASn4Z0=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Top Level Class Diagram", + "visible": true, + "defaultDiagram": false, + "ownedViews": [ + { + "_type": "UMLClassView", + "_id": "AAAAAAFk72k8MQTNeoc=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk72k8MgTO68E=", + "_parent": { + "$ref": "AAAAAAFk72k8MQTNeoc=" + }, + "model": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk72k8MgTP/Uo=", + "_parent": { + "$ref": "AAAAAAFk72k8MgTO68E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -260, + "top": 82, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72k8MgTQwMU=", + "_parent": { + "$ref": "AAAAAAFk72k8MgTO68E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 461, + "top": 199, + "width": 186, + "height": 13, + "autoResize": false, + "underline": false, + "text": "UIView (WebCache)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72k8MgTR9EQ=", + "_parent": { + "$ref": "AAAAAAFk72k8MgTO68E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 461, + "top": 214, + "width": 186, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72k8MgTSn4M=", + "_parent": { + "$ref": "AAAAAAFk72k8MgTO68E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -260, + "top": 82, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 456, + "top": 192, + "width": 196, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk72k8MgTP/Uo=" + }, + "nameLabel": { + "$ref": "AAAAAAFk72k8MgTQwMU=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk72k8MgTR9EQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72k8MgTSn4M=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk72k8MgTTCb4=", + "_parent": { + "$ref": "AAAAAAFk72k8MQTNeoc=" + }, + "model": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 456, + "top": 232, + "width": 196, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk72k8MwTUj3g=", + "_parent": { + "$ref": "AAAAAAFk72k8MQTNeoc=" + }, + "model": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72k8QATzNkY=", + "_parent": { + "$ref": "AAAAAAFk72k8MwTUj3g=" + }, + "model": { + "$ref": "AAAAAAFXmsqK3idvzv0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 461, + "top": 247, + "width": 186, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sd_internalSetImageWithURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 456, + "top": 242, + "width": 196, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk72k8MwTVpy8=", + "_parent": { + "$ref": "AAAAAAFk72k8MQTNeoc=" + }, + "model": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -130, + "top": 41, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk72k8MwTWic8=", + "_parent": { + "$ref": "AAAAAAFk72k8MQTNeoc=" + }, + "model": { + "$ref": "AAAAAAFXmsqK3SdrXmw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -130, + "top": 41, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 456, + "top": 192, + "width": 196, + "height": 73, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk72k8MgTO68E=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk72k8MgTTCb4=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk72k8MwTUj3g=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk72k8MwTVpy8=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk72k8MwTWic8=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk72lBKAT3cuk=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFXmnErIidawX8=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk72lBKAT4KWI=", + "_parent": { + "$ref": "AAAAAAFk72lBKAT3cuk=" + }, + "model": { + "$ref": "AAAAAAFXmnErIidawX8=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk72lBKAT5/Cw=", + "_parent": { + "$ref": "AAAAAAFk72lBKAT4KWI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1400, + "top": -320, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72lBKAT6zDU=", + "_parent": { + "$ref": "AAAAAAFk72lBKAT4KWI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 197, + "top": 23, + "width": 230, + "height": 13, + "autoResize": false, + "underline": false, + "text": "UIImageView (HighlightedWebCache)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72lBKAT7WWQ=", + "_parent": { + "$ref": "AAAAAAFk72lBKAT4KWI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 197, + "top": 38, + "width": 230, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72lBKAT809Q=", + "_parent": { + "$ref": "AAAAAAFk72lBKAT4KWI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1400, + "top": -320, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 192, + "top": 16, + "width": 240, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk72lBKAT5/Cw=" + }, + "nameLabel": { + "$ref": "AAAAAAFk72lBKAT6zDU=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk72lBKAT7WWQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72lBKAT809Q=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk72lBKAT9KEA=", + "_parent": { + "$ref": "AAAAAAFk72lBKAT3cuk=" + }, + "model": { + "$ref": "AAAAAAFXmnErIidawX8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 192, + "top": 56, + "width": 240, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk72lBKQT+O1A=", + "_parent": { + "$ref": "AAAAAAFk72lBKAT3cuk=" + }, + "model": { + "$ref": "AAAAAAFXmnErIidawX8=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72lBOwUofsk=", + "_parent": { + "$ref": "AAAAAAFk72lBKQT+O1A=" + }, + "model": { + "$ref": "AAAAAAFXmnErIideM/I=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 197, + "top": 71, + "width": 230, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sd_setHighlightedImageWithURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 192, + "top": 66, + "width": 240, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk72lBKQT/tIk=", + "_parent": { + "$ref": "AAAAAAFk72lBKAT3cuk=" + }, + "model": { + "$ref": "AAAAAAFXmnErIidawX8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -700, + "top": -160, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk72lBKQUAd3I=", + "_parent": { + "$ref": "AAAAAAFk72lBKAT3cuk=" + }, + "model": { + "$ref": "AAAAAAFXmnErIidawX8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -700, + "top": -160, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 192, + "top": 16, + "width": 240, + "height": 73, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk72lBKAT4KWI=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk72lBKAT9KEA=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk72lBKQT+O1A=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk72lBKQT/tIk=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk72lBKQUAd3I=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk72lBKQUBEog=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFk0Q9x+qJrGM4=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72lBKQUC3tY=", + "_parent": { + "$ref": "AAAAAAFk72lBKQUBEog=" + }, + "model": { + "$ref": "AAAAAAFk0Q9x+qJrGM4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 440, + "top": 121, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72lBKQUBEog=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72lBKgUDzkA=", + "_parent": { + "$ref": "AAAAAAFk72lBKQUBEog=" + }, + "model": { + "$ref": "AAAAAAFk0Q9x+qJrGM4=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 449, + "top": 109, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72lBKQUBEog=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72lBKgUEJGE=", + "_parent": { + "$ref": "AAAAAAFk72lBKQUBEog=" + }, + "model": { + "$ref": "AAAAAAFk0Q9x+qJrGM4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 423, + "top": 146, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72lBKQUBEog=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk72k8MQTNeoc=" + }, + "tail": { + "$ref": "AAAAAAFk72lBKAT3cuk=" + }, + "lineStyle": 1, + "points": "362:89;502:191", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk72lBKQUC3tY=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk72lBKgUDzkA=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72lBKgUEJGE=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk72lv0wUxPyU=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk72lv0wUyNOk=", + "_parent": { + "$ref": "AAAAAAFk72lv0wUxPyU=" + }, + "model": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk72lv0wUzvOQ=", + "_parent": { + "$ref": "AAAAAAFk72lv0wUyNOk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1160, + "top": -154, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72lv0wU03SQ=", + "_parent": { + "$ref": "AAAAAAFk72lv0wUyNOk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 23, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "UIImageView (WebCache)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72lv0wU1+04=", + "_parent": { + "$ref": "AAAAAAFk72lv0wUyNOk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 38, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72lv0wU2GDY=", + "_parent": { + "$ref": "AAAAAAFk72lv0wUyNOk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1160, + "top": -154, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 16, + "width": 168, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk72lv0wUzvOQ=" + }, + "nameLabel": { + "$ref": "AAAAAAFk72lv0wU03SQ=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk72lv0wU1+04=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72lv0wU2GDY=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk72lv1AU3bIg=", + "_parent": { + "$ref": "AAAAAAFk72lv0wUxPyU=" + }, + "model": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 56, + "width": 168, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk72lv1AU43kg=", + "_parent": { + "$ref": "AAAAAAFk72lv0wUxPyU=" + }, + "model": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72lv4QViE1w=", + "_parent": { + "$ref": "AAAAAAFk72lv1AU43kg=" + }, + "model": { + "$ref": "AAAAAAFUmPuK4C6yWrI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 71, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sd_setImageWithURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 66, + "width": 168, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk72lv1AU5T4o=", + "_parent": { + "$ref": "AAAAAAFk72lv0wUxPyU=" + }, + "model": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -580, + "top": -77, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk72lv1AU6p0Q=", + "_parent": { + "$ref": "AAAAAAFk72lv0wUxPyU=" + }, + "model": { + "$ref": "AAAAAAFUmPtmMC6BqlU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -580, + "top": -77, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 16, + "top": 16, + "width": 168, + "height": 73, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk72lv0wUyNOk=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk72lv1AU3bIg=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk72lv1AU43kg=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk72lv1AU5T4o=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk72lv1AU6p0Q=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk72lv1QU7UvE=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFk0Q5c9Jg/0Jc=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72lv1gU8cvQ=", + "_parent": { + "$ref": "AAAAAAFk72lv1QU7UvE=" + }, + "model": { + "$ref": "AAAAAAFk0Q5c9Jg/0Jc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 326, + "top": 118, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72lv1QU7UvE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72lv1gU9UZQ=", + "_parent": { + "$ref": "AAAAAAFk72lv1QU7UvE=" + }, + "model": { + "$ref": "AAAAAAFk0Q5c9Jg/0Jc=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 331, + "top": 104, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72lv1QU7UvE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72lv1gU+FSE=", + "_parent": { + "$ref": "AAAAAAFk72lv1QU7UvE=" + }, + "model": { + "$ref": "AAAAAAFk0Q5c9Jg/0Jc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 315, + "top": 145, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72lv1QU7UvE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk72k8MQTNeoc=" + }, + "tail": { + "$ref": "AAAAAAFk72lv0wUxPyU=" + }, + "lineStyle": 1, + "points": "184:85;458:191", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk72lv1gU8cvQ=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk72lv1gU9UZQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72lv1gU+FSE=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk72mJEQVqUmk=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFk7CZN3IZtF9w=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk72mJEQVrX40=", + "_parent": { + "$ref": "AAAAAAFk72mJEQVqUmk=" + }, + "model": { + "$ref": "AAAAAAFk7CZN3IZtF9w=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk72mJEQVsZmc=", + "_parent": { + "$ref": "AAAAAAFk72mJEQVrX40=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -242, + "top": -366, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72mJEQVteKs=", + "_parent": { + "$ref": "AAAAAAFk72mJEQVrX40=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 445, + "top": 23, + "width": 222, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDAnimatedImageView (WebCache)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72mJEQVuQlg=", + "_parent": { + "$ref": "AAAAAAFk72mJEQVrX40=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 445, + "top": 38, + "width": 222, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72mJEQVvrP0=", + "_parent": { + "$ref": "AAAAAAFk72mJEQVrX40=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -242, + "top": -366, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 440, + "top": 16, + "width": 232, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk72mJEQVsZmc=" + }, + "nameLabel": { + "$ref": "AAAAAAFk72mJEQVteKs=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk72mJEQVuQlg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72mJEQVvrP0=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk72mJEQVwyVw=", + "_parent": { + "$ref": "AAAAAAFk72mJEQVqUmk=" + }, + "model": { + "$ref": "AAAAAAFk7CZN3IZtF9w=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 440, + "top": 56, + "width": 232, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk72mJEQVxABc=", + "_parent": { + "$ref": "AAAAAAFk72mJEQVqUmk=" + }, + "model": { + "$ref": "AAAAAAFk7CZN3IZtF9w=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72mJGAWbgXc=", + "_parent": { + "$ref": "AAAAAAFk72mJEQVxABc=" + }, + "model": { + "$ref": "AAAAAAFk7CbOtYiUask=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 445, + "top": 71, + "width": 222, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sd_setImageWithURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 440, + "top": 66, + "width": 232, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk72mJEQVyodw=", + "_parent": { + "$ref": "AAAAAAFk72mJEQVqUmk=" + }, + "model": { + "$ref": "AAAAAAFk7CZN3IZtF9w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -121, + "top": -183, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk72mJEgVzWGI=", + "_parent": { + "$ref": "AAAAAAFk72mJEQVqUmk=" + }, + "model": { + "$ref": "AAAAAAFk7CZN3IZtF9w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -121, + "top": -183, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 440, + "top": 16, + "width": 232, + "height": 73, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk72mJEQVrX40=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk72mJEQVwyVw=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk72mJEQVxABc=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk72mJEQVyodw=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk72mJEgVzWGI=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk72mJEgV02EM=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFk7CeGFosTNLw=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72mJEgV1nwc=", + "_parent": { + "$ref": "AAAAAAFk72mJEgV02EM=" + }, + "model": { + "$ref": "AAAAAAFk7CeGFosTNLw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 568, + "top": 134, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72mJEgV02EM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72mJEgV2bvM=", + "_parent": { + "$ref": "AAAAAAFk72mJEgV02EM=" + }, + "model": { + "$ref": "AAAAAAFk7CeGFosTNLw=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 583, + "top": 134, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72mJEgV02EM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72mJEgV3m2o=", + "_parent": { + "$ref": "AAAAAAFk72mJEgV02EM=" + }, + "model": { + "$ref": "AAAAAAFk7CeGFosTNLw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 539, + "top": 133, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72mJEgV02EM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk72k8MQTNeoc=" + }, + "tail": { + "$ref": "AAAAAAFk72mJEQVqUmk=" + }, + "lineStyle": 1, + "points": "555:89;553:191", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk72mJEgV1nwc=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk72mJEgV2bvM=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72mJEgV3m2o=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk72mTugWi4xc=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk72mTugWjqC8=", + "_parent": { + "$ref": "AAAAAAFk72mTugWi4xc=" + }, + "model": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk72mTugWkAiA=", + "_parent": { + "$ref": "AAAAAAFk72mTugWjqC8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -446, + "top": -608, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72mTugWl3QU=", + "_parent": { + "$ref": "AAAAAAFk72mTugWjqC8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 685, + "top": 23, + "width": 195, + "height": 13, + "autoResize": false, + "underline": false, + "text": "MKAnnotationView (WebCache)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72mTugWmInw=", + "_parent": { + "$ref": "AAAAAAFk72mTugWjqC8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 685, + "top": 38, + "width": 195, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72mTugWnspw=", + "_parent": { + "$ref": "AAAAAAFk72mTugWjqC8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -446, + "top": -608, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 680, + "top": 16, + "width": 205, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk72mTugWkAiA=" + }, + "nameLabel": { + "$ref": "AAAAAAFk72mTugWl3QU=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk72mTugWmInw=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72mTugWnspw=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk72mTugWo+rk=", + "_parent": { + "$ref": "AAAAAAFk72mTugWi4xc=" + }, + "model": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 680, + "top": 56, + "width": 205, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk72mTugWpgOU=", + "_parent": { + "$ref": "AAAAAAFk72mTugWi4xc=" + }, + "model": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72mTwgXTw0Q=", + "_parent": { + "$ref": "AAAAAAFk72mTugWpgOU=" + }, + "model": { + "$ref": "AAAAAAFUmPndIiv0KoI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 685, + "top": 71, + "width": 195, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sd_setImageWithURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 680, + "top": 66, + "width": 205, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk72mTugWqn60=", + "_parent": { + "$ref": "AAAAAAFk72mTugWi4xc=" + }, + "model": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -223, + "top": -304, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk72mTugWrn30=", + "_parent": { + "$ref": "AAAAAAFk72mTugWi4xc=" + }, + "model": { + "$ref": "AAAAAAFUmPjp9CtnN2Y=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -223, + "top": -304, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 680, + "top": 16, + "width": 205, + "height": 73, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk72mTugWjqC8=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk72mTugWo+rk=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk72mTugWpgOU=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk72mTugWqn60=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk72mTugWrn30=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk72mTuwWsReI=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFk0RCPR6y62U8=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72mTuwWtVRo=", + "_parent": { + "$ref": "AAAAAAFk72mTuwWsReI=" + }, + "model": { + "$ref": "AAAAAAFk0RCPR6y62U8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 676, + "top": 145, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72mTuwWsReI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72mTuwWuiFY=", + "_parent": { + "$ref": "AAAAAAFk72mTuwWsReI=" + }, + "model": { + "$ref": "AAAAAAFk0RCPR6y62U8=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 685, + "top": 157, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72mTuwWsReI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72mTuwWvmlA=", + "_parent": { + "$ref": "AAAAAAFk72mTuwWsReI=" + }, + "model": { + "$ref": "AAAAAAFk0RCPR6y62U8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 657, + "top": 122, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72mTuwWsReI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk72k8MQTNeoc=" + }, + "tail": { + "$ref": "AAAAAAFk72mTugWi4xc=" + }, + "lineStyle": 1, + "points": "734:89;601:191", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk72mTuwWtVRo=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk72mTuwWuiFY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72mTuwWvmlA=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk72mkYgXa4A0=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk72mkYgXbwfc=", + "_parent": { + "$ref": "AAAAAAFk72mkYgXa4A0=" + }, + "model": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk72mkYgXcPg8=", + "_parent": { + "$ref": "AAAAAAFk72mkYgXbwfc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 490, + "top": -904, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72mkYgXd4sQ=", + "_parent": { + "$ref": "AAAAAAFk72mkYgXbwfc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 23, + "width": 142, + "height": 13, + "autoResize": false, + "underline": false, + "text": "UIButton (WebCache)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72mkYgXeWZE=", + "_parent": { + "$ref": "AAAAAAFk72mkYgXbwfc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 38, + "width": 142, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72mkYgXfZis=", + "_parent": { + "$ref": "AAAAAAFk72mkYgXbwfc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 490, + "top": -904, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 896, + "top": 16, + "width": 152, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk72mkYgXcPg8=" + }, + "nameLabel": { + "$ref": "AAAAAAFk72mkYgXd4sQ=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk72mkYgXeWZE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72mkYgXfZis=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk72mkYgXgvEQ=", + "_parent": { + "$ref": "AAAAAAFk72mkYgXa4A0=" + }, + "model": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 896, + "top": 56, + "width": 152, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk72mkYgXhTkA=", + "_parent": { + "$ref": "AAAAAAFk72mkYgXa4A0=" + }, + "model": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72mkagYLBRk=", + "_parent": { + "$ref": "AAAAAAFk72mkYgXhTkA=" + }, + "model": { + "$ref": "AAAAAAFUmPsYkS1rEno=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 71, + "width": 142, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sd_setImageWithURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 896, + "top": 66, + "width": 152, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk72mkYgXimr4=", + "_parent": { + "$ref": "AAAAAAFk72mkYgXa4A0=" + }, + "model": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 245, + "top": -452, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk72mkYgXjac8=", + "_parent": { + "$ref": "AAAAAAFk72mkYgXa4A0=" + }, + "model": { + "$ref": "AAAAAAFUmPoFSiy4ZTk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 245, + "top": -452, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 896, + "top": 16, + "width": 152, + "height": 73, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk72mkYgXbwfc=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk72mkYgXgvEQ=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk72mkYgXhTkA=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk72mkYgXimr4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk72mkYgXjac8=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk72mkZAXkq5Q=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFk0Q/6pKhroeQ=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72mkZAXlLJQ=", + "_parent": { + "$ref": "AAAAAAFk72mkZAXkq5Q=" + }, + "model": { + "$ref": "AAAAAAFk0Q/6pKhroeQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 773, + "top": 144, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72mkZAXkq5Q=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72mkZAXmH+s=", + "_parent": { + "$ref": "AAAAAAFk72mkZAXkq5Q=" + }, + "model": { + "$ref": "AAAAAAFk0Q/6pKhroeQ=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 779, + "top": 158, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72mkZAXkq5Q=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72mkZAXnUXk=", + "_parent": { + "$ref": "AAAAAAFk72mkZAXkq5Q=" + }, + "model": { + "$ref": "AAAAAAFk0Q/6pKhroeQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 762, + "top": 117, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72mkZAXkq5Q=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk72k8MQTNeoc=" + }, + "tail": { + "$ref": "AAAAAAFk72mkYgXa4A0=" + }, + "lineStyle": 1, + "points": "895:84;641:191", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk72mkZAXlLJQ=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk72mkZAXmH+s=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72mkZAXnUXk=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk72parwYbieU=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk72parwYcxT8=", + "_parent": { + "$ref": "AAAAAAFk72parwYbieU=" + }, + "model": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk72parwYdXFE=", + "_parent": { + "$ref": "AAAAAAFk72parwYcxT8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -98, + "top": -58, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72parwYeqLA=", + "_parent": { + "$ref": "AAAAAAFk72parwYcxT8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1069, + "top": 23, + "width": 256, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImagePrefetcher", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72pasAYf1G0=", + "_parent": { + "$ref": "AAAAAAFk72parwYcxT8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1069, + "top": 38, + "width": 256, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72pasAYg51U=", + "_parent": { + "$ref": "AAAAAAFk72parwYcxT8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -98, + "top": -58, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1064, + "top": 16, + "width": 266, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk72parwYdXFE=" + }, + "nameLabel": { + "$ref": "AAAAAAFk72parwYeqLA=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk72pasAYf1G0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72pasAYg51U=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk72pasAYhdW8=", + "_parent": { + "$ref": "AAAAAAFk72parwYbieU=" + }, + "model": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk72pavAZBCm4=", + "_parent": { + "$ref": "AAAAAAFk72pasAYhdW8=" + }, + "model": { + "$ref": "AAAAAAFUmM4zy8syqFU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1069, + "top": 61, + "width": 256, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedImagePrefetcher", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk72pavQZE5gI=", + "_parent": { + "$ref": "AAAAAAFk72pasAYhdW8=" + }, + "model": { + "$ref": "AAAAAAFk0LGPQUYY/Mk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1069, + "top": 76, + "width": 256, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+delegate: SDWebImagePrefetcherDelegate", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk72pavgZHONM=", + "_parent": { + "$ref": "AAAAAAFk72pasAYhdW8=" + }, + "model": { + "$ref": "AAAAAAFUmMwm7Mnxz9U=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1069, + "top": 91, + "width": 256, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+options: SDWebImageOptions", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1064, + "top": 56, + "width": 266, + "height": 53, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk72pasAYiiI8=", + "_parent": { + "$ref": "AAAAAAFk72parwYbieU=" + }, + "model": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72pavgZKU8g=", + "_parent": { + "$ref": "AAAAAAFk72pasAYiiI8=" + }, + "model": { + "$ref": "AAAAAAFUmM3dVsr1bHY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1069, + "top": 114, + "width": 256, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+prefetchURLs:()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72pavwZNxBg=", + "_parent": { + "$ref": "AAAAAAFk72pasAYiiI8=" + }, + "model": { + "$ref": "AAAAAAFUmNCMgs5kwbc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1069, + "top": 129, + "width": 256, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cancelPrefetching()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1064, + "top": 109, + "width": 266, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk72pasAYjh+0=", + "_parent": { + "$ref": "AAAAAAFk72parwYbieU=" + }, + "model": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -49, + "top": -29, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk72pasQYkYeA=", + "_parent": { + "$ref": "AAAAAAFk72parwYbieU=" + }, + "model": { + "$ref": "AAAAAAFUkhgItozoKPM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -49, + "top": -29, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1064, + "top": 16, + "width": 266, + "height": 131, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk72parwYcxT8=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk72pasAYhdW8=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk72pasAYiiI8=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk72pasAYjh+0=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk72pasQYkYeA=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk72r2sQZSp+c=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk72r2sQZTwZc=", + "_parent": { + "$ref": "AAAAAAFk72r2sQZSp+c=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk72r2sQZUagc=", + "_parent": { + "$ref": "AAAAAAFk72r2sQZTwZc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -516, + "top": -60, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72r2sgZVU6E=", + "_parent": { + "$ref": "AAAAAAFk72r2sQZTwZc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 343, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageManager", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72r2sgZWdJE=", + "_parent": { + "$ref": "AAAAAAFk72r2sQZTwZc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 358, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72r2sgZXeUI=", + "_parent": { + "$ref": "AAAAAAFk72r2sQZTwZc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -516, + "top": -60, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 288, + "top": 336, + "width": 519, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk72r2sQZUagc=" + }, + "nameLabel": { + "$ref": "AAAAAAFk72r2sgZVU6E=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk72r2sgZWdJE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72r2sgZXeUI=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk72r2sgZYYII=", + "_parent": { + "$ref": "AAAAAAFk72r2sQZSp+c=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk72r21gamCA8=", + "_parent": { + "$ref": "AAAAAAFk72r2sgZYYII=" + }, + "model": { + "$ref": "AAAAAAFUkiBj3o4EzZs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 381, + "width": 509, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedManager", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk72r21wappvQ=", + "_parent": { + "$ref": "AAAAAAFk72r2sgZYYII=" + }, + "model": { + "$ref": "AAAAAAFky2HbvA+NZl4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 396, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+delegate: SDWebImageManagerDelegate", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk72r21wasBuI=", + "_parent": { + "$ref": "AAAAAAFk72r2sgZYYII=" + }, + "model": { + "$ref": "AAAAAAFky2J/rxG0jPU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 411, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageCache: SDImageCache", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk72r22Aav/Pc=", + "_parent": { + "$ref": "AAAAAAFk72r2sgZYYII=" + }, + "model": { + "$ref": "AAAAAAFky2KxrxL/YZE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 426, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageLoader: SDImageLoader", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk72r22AayZQo=", + "_parent": { + "$ref": "AAAAAAFk72r2sgZYYII=" + }, + "model": { + "$ref": "AAAAAAFky2Ld4BRKPO4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 441, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+transformer: SDImageTransformer", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk72r22Qa1JvQ=", + "_parent": { + "$ref": "AAAAAAFk72r2sgZYYII=" + }, + "model": { + "$ref": "AAAAAAFky2MdORXm73I=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 456, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cacheKeyFilter: SDWebImageCacheKeyFilter", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk72r22Qa4BgM=", + "_parent": { + "$ref": "AAAAAAFk72r2sgZYYII=" + }, + "model": { + "$ref": "AAAAAAFky2NDyRcxc0E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 471, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cacheSerializer: SDWebImageCacheSerializer", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk72r22ga7tV8=", + "_parent": { + "$ref": "AAAAAAFk72r2sgZYYII=" + }, + "model": { + "$ref": "AAAAAAFky2OkAhh8hEE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 486, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+running", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk72r22ga+AAk=", + "_parent": { + "$ref": "AAAAAAFk72r2sgZYYII=" + }, + "model": { + "$ref": "AAAAAAFky2PUsxnHAYw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 501, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+defaultImageCache: SDImageCache", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk72r22wbBq1U=", + "_parent": { + "$ref": "AAAAAAFk72r2sgZYYII=" + }, + "model": { + "$ref": "AAAAAAFky2P6zBsSQ7s=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 516, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+defaultImageLoader: SDImageLoader", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 288, + "top": 376, + "width": 519, + "height": 158, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk72r2sgZZwRE=", + "_parent": { + "$ref": "AAAAAAFk72r2sQZSp+c=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72r22wbE/yI=", + "_parent": { + "$ref": "AAAAAAFk72r2sgZZwRE=" + }, + "model": { + "$ref": "AAAAAAFky2Q6HRxddGo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 539, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(cache, loader)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72r23AbHM2I=", + "_parent": { + "$ref": "AAAAAAFk72r2sgZZwRE=" + }, + "model": { + "$ref": "AAAAAAFUkh/xZ44AqYk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 554, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+loadImage(url, options, context, progressBlock, completedBlock): CombinedOperatiom", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72r23AbKQSg=", + "_parent": { + "$ref": "AAAAAAFk72r2sgZZwRE=" + }, + "model": { + "$ref": "AAAAAAFUmNLtYNLc08o=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 569, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cancelAll()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72r23QbNJtI=", + "_parent": { + "$ref": "AAAAAAFk72r2sgZZwRE=" + }, + "model": { + "$ref": "AAAAAAFUmNORx9Q1mi4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 584, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cacheKey(url): String", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 288, + "top": 534, + "width": 519, + "height": 68, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk72r2sgZa+Vk=", + "_parent": { + "$ref": "AAAAAAFk72r2sQZSp+c=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -258, + "top": -30, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk72r2sgZbX40=", + "_parent": { + "$ref": "AAAAAAFk72r2sQZSp+c=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -258, + "top": -30, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 288, + "top": 336, + "width": 519, + "height": 266, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk72r2sQZTwZc=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk72r2sgZYYII=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk72r2sgZZwRE=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk72r2sgZa+Vk=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk72r2sgZbX40=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk72r2tQZclPM=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZcn8MSQ=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72r2tQZd77c=", + "_parent": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZcn8MSQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1169, + "top": 433, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72r2tgZevt4=", + "_parent": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZcn8MSQ=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1154, + "top": 433, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72r2tgZfJvQ=", + "_parent": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZcn8MSQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1199, + "top": 434, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72r2tgZgo6w=", + "_parent": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn92Qw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 831, + "top": 419, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72r2tgZhwwg=", + "_parent": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn92Qw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 834, + "top": 405, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72r2tgZiS6o=", + "_parent": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn92Qw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 827, + "top": 446, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72r2tgZjB8s=", + "_parent": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn+nz8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1169, + "top": 165, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72r2tgZkVgQ=", + "_parent": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn+nz8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1155, + "top": 168, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72r2tgZltbA=", + "_parent": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn+nz8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1196, + "top": 161, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk72r2tgZmv6s=", + "_parent": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn92Qw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk72r2twZnP3M=", + "_parent": { + "$ref": "AAAAAAFk72r2tQZclPM=" + }, + "model": { + "$ref": "AAAAAAFUmMzgZsn+nz8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk72parwYbieU=" + }, + "tail": { + "$ref": "AAAAAAFk72r2sQZSp+c=" + }, + "lineStyle": 0, + "points": "806:440;1184:440;1184:146", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk72r2tQZd77c=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk72r2tgZevt4=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72r2tgZfJvQ=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk72r2tgZgo6w=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk72r2tgZhwwg=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk72r2tgZiS6o=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk72r2tgZjB8s=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk72r2tgZkVgQ=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk72r2tgZltbA=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk72r2tgZmv6s=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk72r2twZnP3M=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk72r2uAZoJQQ=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFk0RKU97ifqxY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72r2uAZpNDU=", + "_parent": { + "$ref": "AAAAAAFk72r2uAZoJQQ=" + }, + "model": { + "$ref": "AAAAAAFk0RKU97ifqxY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 566, + "top": 293, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72r2uAZoJQQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72r2uQZqhWc=", + "_parent": { + "$ref": "AAAAAAFk72r2uAZoJQQ=" + }, + "model": { + "$ref": "AAAAAAFk0RKU97ifqxY=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 581, + "top": 293, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72r2uAZoJQQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72r2uQZrK5U=", + "_parent": { + "$ref": "AAAAAAFk72r2uAZoJQQ=" + }, + "model": { + "$ref": "AAAAAAFk0RKU97ifqxY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 537, + "top": 294, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72r2uAZoJQQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk72r2sQZSp+c=" + }, + "tail": { + "$ref": "AAAAAAFk72k8MQTNeoc=" + }, + "lineStyle": 0, + "points": "552:264;552:336", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk72r2uAZpNDU=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk72r2uQZqhWc=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72r2uQZrK5U=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk72tIgQeCJzw=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk72tIgQeDiVE=", + "_parent": { + "$ref": "AAAAAAFk72tIgQeCJzw=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk72tIgQeEiaE=", + "_parent": { + "$ref": "AAAAAAFk72tIgQeDiVE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 381, + "width": 199, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72tIgQeF80o=", + "_parent": { + "$ref": "AAAAAAFk72tIgQeDiVE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 396, + "width": 199, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageManagerDelegate", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72tIgQeG22k=", + "_parent": { + "$ref": "AAAAAAFk72tIgQeDiVE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 411, + "width": 199, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72tIgQeHhZ4=", + "_parent": { + "$ref": "AAAAAAFk72tIgQeDiVE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -196, + "top": -144, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 376, + "width": 209, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk72tIgQeEiaE=" + }, + "nameLabel": { + "$ref": "AAAAAAFk72tIgQeF80o=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk72tIgQeG22k=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72tIgQeHhZ4=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk72tIggeIsAs=", + "_parent": { + "$ref": "AAAAAAFk72tIgQeCJzw=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -98, + "top": -72, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk72tIggeJ5mw=", + "_parent": { + "$ref": "AAAAAAFk72tIgQeCJzw=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72tIjgfOR0Y=", + "_parent": { + "$ref": "AAAAAAFk72tIggeJ5mw=" + }, + "model": { + "$ref": "AAAAAAFUkh6LiI3wgxM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 434, + "width": 223, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+shouldDownloadImageForURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72tIjwfRDp8=", + "_parent": { + "$ref": "AAAAAAFk72tIggeJ5mw=" + }, + "model": { + "$ref": "AAAAAAFUkh65uI30vRk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 449, + "width": 223, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+shouldBlockFailedURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 429, + "width": 233, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk72tIggeKdAE=", + "_parent": { + "$ref": "AAAAAAFk72tIgQeCJzw=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -98, + "top": -72, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk72tIggeLe6A=", + "_parent": { + "$ref": "AAAAAAFk72tIgQeCJzw=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -98, + "top": -72, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 16, + "top": 376, + "width": 233, + "height": 91, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk72tIgQeDiVE=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk72tIggeIsAs=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk72tIggeJ5mw=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk72tIggeKdAE=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk72tIggeLe6A=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk72tIgweMV/g=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAIwc4=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72tIgweNP3A=", + "_parent": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAIwc4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 268, + "top": 379, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72tIgweOMfc=", + "_parent": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAIwc4=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 268, + "top": 364, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72tIgwePgUc=", + "_parent": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAIwc4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 268, + "top": 409, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72tIgweQutU=", + "_parent": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAJw9E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 273, + "top": 379, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72tIgweRAcA=", + "_parent": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAJw9E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 276, + "top": 365, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72tIgweSHdg=", + "_parent": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAJw9E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 269, + "top": 406, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72tIgweTN1U=", + "_parent": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAKXzo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 262, + "top": 379, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72tIgweUkoc=", + "_parent": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAKXzo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 259, + "top": 365, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72tIhAeVBZQ=", + "_parent": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAKXzo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 266, + "top": 406, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk72tIhAeWUe8=", + "_parent": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAJw9E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk72tIhAeXVh0=", + "_parent": { + "$ref": "AAAAAAFk72tIgweMV/g=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAKXzo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk72r2sQZSp+c=" + }, + "tail": { + "$ref": "AAAAAAFk72tIgQeCJzw=" + }, + "lineStyle": 0, + "points": "248:400;288:400", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk72tIgweNP3A=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk72tIgweOMfc=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72tIgwePgUc=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk72tIgweQutU=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk72tIgweRAcA=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk72tIgweSHdg=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk72tIgweTN1U=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk72tIgweUkoc=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk72tIhAeVBZQ=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk72tIhAeWUe8=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk72tIhAeXVh0=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk72v+QwoUB58=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk72v+QwoVQ4M=", + "_parent": { + "$ref": "AAAAAAFk72v+QwoUB58=" + }, + "model": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk72v+QwoW68M=", + "_parent": { + "$ref": "AAAAAAFk72v+QwoVQ4M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 29, + "width": 209, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72v+QwoXfLU=", + "_parent": { + "$ref": "AAAAAAFk72v+QwoVQ4M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 44, + "width": 209, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImagePrefetcherDelegate", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72v+RAoYtVE=", + "_parent": { + "$ref": "AAAAAAFk72v+QwoVQ4M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 59, + "width": 209, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk72v+RAoZTXY=", + "_parent": { + "$ref": "AAAAAAFk72v+QwoVQ4M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 14, + "top": -330, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1392, + "top": 24, + "width": 219, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk72v+QwoW68M=" + }, + "nameLabel": { + "$ref": "AAAAAAFk72v+QwoXfLU=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk72v+RAoYtVE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72v+RAoZTXY=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk72v+RAoaRkQ=", + "_parent": { + "$ref": "AAAAAAFk72v+QwoUB58=" + }, + "model": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 7, + "top": -165, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk72v+RAobkV0=", + "_parent": { + "$ref": "AAAAAAFk72v+QwoUB58=" + }, + "model": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72v+UgpjkME=", + "_parent": { + "$ref": "AAAAAAFk72v+RAobkV0=" + }, + "model": { + "$ref": "AAAAAAFUkht/NI1jZE4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 82, + "width": 233, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+didPrefetchURL:()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk72v+Uwpm33M=", + "_parent": { + "$ref": "AAAAAAFk72v+RAobkV0=" + }, + "model": { + "$ref": "AAAAAAFUkhu8u41n4Ps=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 97, + "width": 233, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+didFinishWithTotalCount:()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1392, + "top": 77, + "width": 243, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk72v+RAoc8tQ=", + "_parent": { + "$ref": "AAAAAAFk72v+QwoUB58=" + }, + "model": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 7, + "top": -165, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk72v+RAod9ts=", + "_parent": { + "$ref": "AAAAAAFk72v+QwoUB58=" + }, + "model": { + "$ref": "AAAAAAFUkhg5/4zs5zU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 7, + "top": -165, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1392, + "top": 24, + "width": 243, + "height": 102, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk72v+QwoVQ4M=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk72v+RAoaRkQ=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk72v+RAobkV0=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk72v+RAoc8tQ=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk72v+RAod9ts=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk72v+RQoeia8=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFUmM8TqsupT40=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72v+RQof+SM=", + "_parent": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "model": { + "$ref": "AAAAAAFUmM8TqsupT40=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1359, + "top": 87, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72v+RQogQaY=", + "_parent": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "model": { + "$ref": "AAAAAAFUmM8TqsupT40=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1359, + "top": 102, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72v+RQohL10=", + "_parent": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "model": { + "$ref": "AAAAAAFUmM8TqsupT40=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1360, + "top": 57, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72v+RQoiz4s=", + "_parent": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuqc7A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1366, + "top": 86, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72v+RQojPd8=", + "_parent": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuqc7A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1363, + "top": 100, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72v+RQokhF0=", + "_parent": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuqc7A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1370, + "top": 59, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72v+RQolA30=", + "_parent": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuru94=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1354, + "top": 86, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72v+RQomIkU=", + "_parent": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuru94=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1357, + "top": 100, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk72v+RQonIB4=", + "_parent": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuru94=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1350, + "top": 59, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk72v+RQoohuw=", + "_parent": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuqc7A=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk72v+RQopnGA=", + "_parent": { + "$ref": "AAAAAAFk72v+RQoeia8=" + }, + "model": { + "$ref": "AAAAAAFUmM8Tqsuru94=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk72parwYbieU=" + }, + "tail": { + "$ref": "AAAAAAFk72v+QwoUB58=" + }, + "lineStyle": 0, + "points": "1392:78;1329:78", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk72v+RQof+SM=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk72v+RQogQaY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk72v+RQohL10=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk72v+RQoiz4s=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk72v+RQojPd8=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk72v+RQokhF0=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk72v+RQolA30=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk72v+RQomIkU=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk72v+RQonIB4=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk72v+RQoohuw=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk72v+RQopnGA=" + } + }, + { + "_type": "UMLEnumerationView", + "_id": "AAAAAAFk720oQQ53TEQ=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk720oQQ54xNE=", + "_parent": { + "$ref": "AAAAAAFk720oQQ53TEQ=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk720oQQ55n3Q=", + "_parent": { + "$ref": "AAAAAAFk720oQQ54xNE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 117, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«enumeration»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk720oQQ56zdQ=", + "_parent": { + "$ref": "AAAAAAFk720oQQ54xNE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 132, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageOptions", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk720oQQ579ck=", + "_parent": { + "$ref": "AAAAAAFk720oQQ54xNE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 147, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk720oQQ58GYw=", + "_parent": { + "$ref": "AAAAAAFk720oQQ54xNE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -208, + "top": -248, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 112, + "width": 168, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk720oQQ55n3Q=" + }, + "nameLabel": { + "$ref": "AAAAAAFk720oQQ56zdQ=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk720oQQ579ck=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk720oQQ58GYw=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk720oQQ59xpQ=", + "_parent": { + "$ref": "AAAAAAFk720oQQ53TEQ=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -104, + "top": -124, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk720oQg5+UTM=", + "_parent": { + "$ref": "AAAAAAFk720oQQ53TEQ=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -104, + "top": -124, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk720oQg5/ILE=", + "_parent": { + "$ref": "AAAAAAFk720oQQ53TEQ=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -104, + "top": -124, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk720oQg6AkLU=", + "_parent": { + "$ref": "AAAAAAFk720oQQ53TEQ=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -104, + "top": -124, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLEnumerationLiteralCompartmentView", + "_id": "AAAAAAFk720oQg6BELI=", + "_parent": { + "$ref": "AAAAAAFk720oQQ53TEQ=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "subViews": [ + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk720oUA7APa0=", + "_parent": { + "$ref": "AAAAAAFk720oQg6BELI=" + }, + "model": { + "$ref": "AAAAAAFUkhys4o27Ge0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 170, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "retryFailed", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk720oUQ7DEfc=", + "_parent": { + "$ref": "AAAAAAFk720oQg6BELI=" + }, + "model": { + "$ref": "AAAAAAFUkhza8o2/z9E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 185, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "lowPriority", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk720oUg7GUAA=", + "_parent": { + "$ref": "AAAAAAFk720oQg6BELI=" + }, + "model": { + "$ref": "AAAAAAFUkhzs8o3Fkdk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 200, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "progressiveLoad", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk720oUg7JabM=", + "_parent": { + "$ref": "AAAAAAFk720oQg6BELI=" + }, + "model": { + "$ref": "AAAAAAFUkhz04o3ItAc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 215, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "refreshCached", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk720oUw7MJ1A=", + "_parent": { + "$ref": "AAAAAAFk720oQg6BELI=" + }, + "model": { + "$ref": "AAAAAAFUkhz84Y3L96A=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 230, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "continueInBackground", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk720oUw7PjF4=", + "_parent": { + "$ref": "AAAAAAFk720oQg6BELI=" + }, + "model": { + "$ref": "AAAAAAFUkh0C6Y3O214=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 245, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "handleCookies", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk720oUw7S+/c=", + "_parent": { + "$ref": "AAAAAAFk720oQg6BELI=" + }, + "model": { + "$ref": "AAAAAAFUkh2TUY3YpnQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 260, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "allowInvalidSSLCertificates", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk720oVA7V1TU=", + "_parent": { + "$ref": "AAAAAAFk720oQg6BELI=" + }, + "model": { + "$ref": "AAAAAAFUkh2bqY3bxlE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 275, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "highPriority", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk720oVA7YU9M=", + "_parent": { + "$ref": "AAAAAAFk720oQg6BELI=" + }, + "model": { + "$ref": "AAAAAAFUkh2p4Y3e22E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 290, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "delayPlaceholder", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk720oVA7bCRc=", + "_parent": { + "$ref": "AAAAAAFk720oQg6BELI=" + }, + "model": { + "$ref": "AAAAAAFUkh2x+Y3hQmw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 305, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "transformAnimatedImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk720oVQ7eEew=", + "_parent": { + "$ref": "AAAAAAFk720oQg6BELI=" + }, + "model": { + "$ref": "AAAAAAFUkh31iY3ox50=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 320, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "avoidAutoSetImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk720oVQ7hxgo=", + "_parent": { + "$ref": "AAAAAAFk720oQg6BELI=" + }, + "model": { + "$ref": "AAAAAAFkzPKuPGy7i4M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 335, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "scaleDownLargeImages", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 165, + "width": 168, + "height": 188, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 16, + "top": 112, + "width": 168, + "height": 241, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk720oQQ54xNE=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk720oQQ59xpQ=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk720oQg5+UTM=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk720oQg5/ILE=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk720oQg6AkLU=" + }, + "suppressLiterals": false, + "enumerationLiteralCompartment": { + "$ref": "AAAAAAFk720oQg6BELI=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk720oQw6C2cs=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFk6+vKjo5YRUw=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk720oQw6D15I=", + "_parent": { + "$ref": "AAAAAAFk720oQw6C2cs=" + }, + "model": { + "$ref": "AAAAAAFk6+vKjo5YRUw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 232, + "top": 313, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk720oQw6C2cs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk720oQw6EaQs=", + "_parent": { + "$ref": "AAAAAAFk720oQw6C2cs=" + }, + "model": { + "$ref": "AAAAAAFk6+vKjo5YRUw=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 225, + "top": 326, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk720oQw6C2cs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk720oQw6FFkY=", + "_parent": { + "$ref": "AAAAAAFk720oQw6C2cs=" + }, + "model": { + "$ref": "AAAAAAFk6+vKjo5YRUw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 245, + "top": 286, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk720oQw6C2cs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk720oQQ53TEQ=" + }, + "tail": { + "$ref": "AAAAAAFk72r2sQZSp+c=" + }, + "lineStyle": 1, + "points": "295:335;184:277", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk720oQw6D15I=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk720oQw6EaQs=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk720oQw6FFkY=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk720oQw6G99A=", + "_parent": { + "$ref": "AAAAAAFk72gtuASn4Z0=" + }, + "model": { + "$ref": "AAAAAAFk0RH/JbQKgpI=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk720oQw6HnAU=", + "_parent": { + "$ref": "AAAAAAFk720oQw6G99A=" + }, + "model": { + "$ref": "AAAAAAFk0RH/JbQKgpI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 318, + "top": 240, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk720oQw6G99A=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk720oQw6Ixf0=", + "_parent": { + "$ref": "AAAAAAFk720oQw6G99A=" + }, + "model": { + "$ref": "AAAAAAFk0RH/JbQKgpI=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 318, + "top": 255, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk720oQw6G99A=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk720oQw6JW10=", + "_parent": { + "$ref": "AAAAAAFk720oQw6G99A=" + }, + "model": { + "$ref": "AAAAAAFk0RH/JbQKgpI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 319, + "top": 210, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk720oQw6G99A=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk720oQQ53TEQ=" + }, + "tail": { + "$ref": "AAAAAAFk72k8MQTNeoc=" + }, + "lineStyle": 0, + "points": "456:231;183:231", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk720oQw6HnAU=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk720oQw6Ixf0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk720oQw6JW10=" + } + } + ] + }, + { + "_type": "UMLClassDiagram", + "_id": "AAAAAAFk726wIhJXSAY=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Manager Class Diagram", + "visible": true, + "defaultDiagram": false, + "ownedViews": [ + { + "_type": "UMLClassView", + "_id": "AAAAAAFk727jFxKPv/M=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk727jFxKQJwE=", + "_parent": { + "$ref": "AAAAAAFk727jFxKPv/M=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk727jFxKRQ+Y=", + "_parent": { + "$ref": "AAAAAAFk727jFxKQJwE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 54, + "top": -228, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk727jFxKSjwY=", + "_parent": { + "$ref": "AAAAAAFk727jFxKQJwE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 23, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageManager", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk727jFxKT7jQ=", + "_parent": { + "$ref": "AAAAAAFk727jFxKQJwE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 38, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk727jFxKU1ZQ=", + "_parent": { + "$ref": "AAAAAAFk727jFxKQJwE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 54, + "top": -228, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 416, + "top": 16, + "width": 519, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk727jFxKRQ+Y=" + }, + "nameLabel": { + "$ref": "AAAAAAFk727jFxKSjwY=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk727jFxKT7jQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk727jFxKU1ZQ=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk727jFxKVO34=", + "_parent": { + "$ref": "AAAAAAFk727jFxKPv/M=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk727jKhK1/1o=", + "_parent": { + "$ref": "AAAAAAFk727jFxKVO34=" + }, + "model": { + "$ref": "AAAAAAFUkiBj3o4EzZs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 61, + "width": 509, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedManager", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk727jKxK4WWw=", + "_parent": { + "$ref": "AAAAAAFk727jFxKVO34=" + }, + "model": { + "$ref": "AAAAAAFky2HbvA+NZl4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 76, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+delegate: SDWebImageManagerDelegate", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk727jKxK7hc8=", + "_parent": { + "$ref": "AAAAAAFk727jFxKVO34=" + }, + "model": { + "$ref": "AAAAAAFky2J/rxG0jPU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 91, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageCache: SDImageCache", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk727jKxK+XSQ=", + "_parent": { + "$ref": "AAAAAAFk727jFxKVO34=" + }, + "model": { + "$ref": "AAAAAAFky2KxrxL/YZE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 106, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageLoader: SDImageLoader", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk727jLBLBVKo=", + "_parent": { + "$ref": "AAAAAAFk727jFxKVO34=" + }, + "model": { + "$ref": "AAAAAAFky2Ld4BRKPO4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 121, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+transformer: SDImageTransformer", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk727jLBLEyM0=", + "_parent": { + "$ref": "AAAAAAFk727jFxKVO34=" + }, + "model": { + "$ref": "AAAAAAFky2MdORXm73I=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 136, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cacheKeyFilter: SDWebImageCacheKeyFilter", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk727jLBLHGdE=", + "_parent": { + "$ref": "AAAAAAFk727jFxKVO34=" + }, + "model": { + "$ref": "AAAAAAFky2NDyRcxc0E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 151, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cacheSerializer: SDWebImageCacheSerializer", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk727jLRLKjeU=", + "_parent": { + "$ref": "AAAAAAFk727jFxKVO34=" + }, + "model": { + "$ref": "AAAAAAFky2OkAhh8hEE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 166, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+running", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk727jLRLNBEI=", + "_parent": { + "$ref": "AAAAAAFk727jFxKVO34=" + }, + "model": { + "$ref": "AAAAAAFky2PUsxnHAYw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 181, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+defaultImageCache: SDImageCache", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk727jLRLQVjY=", + "_parent": { + "$ref": "AAAAAAFk727jFxKVO34=" + }, + "model": { + "$ref": "AAAAAAFky2P6zBsSQ7s=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 196, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+defaultImageLoader: SDImageLoader", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 416, + "top": 56, + "width": 519, + "height": 158, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk727jGBKWuEs=", + "_parent": { + "$ref": "AAAAAAFk727jFxKPv/M=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk727jLhLTzAA=", + "_parent": { + "$ref": "AAAAAAFk727jGBKWuEs=" + }, + "model": { + "$ref": "AAAAAAFky2Q6HRxddGo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 219, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(cache, loader)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk727jLhLWJKo=", + "_parent": { + "$ref": "AAAAAAFk727jGBKWuEs=" + }, + "model": { + "$ref": "AAAAAAFUkh/xZ44AqYk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 234, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+loadImage(url, options, context, progressBlock, completedBlock): CombinedOperatiom", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk727jLxLZ46M=", + "_parent": { + "$ref": "AAAAAAFk727jGBKWuEs=" + }, + "model": { + "$ref": "AAAAAAFUmNLtYNLc08o=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 249, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cancelAll()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk727jLxLcqRo=", + "_parent": { + "$ref": "AAAAAAFk727jGBKWuEs=" + }, + "model": { + "$ref": "AAAAAAFUmNORx9Q1mi4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 264, + "width": 509, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cacheKey(url): String", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 416, + "top": 214, + "width": 519, + "height": 68, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk727jGBKXsgE=", + "_parent": { + "$ref": "AAAAAAFk727jFxKPv/M=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 27, + "top": -114, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk727jGBKY7MM=", + "_parent": { + "$ref": "AAAAAAFk727jFxKPv/M=" + }, + "model": { + "$ref": "AAAAAAFUkhwuq42z3w4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 27, + "top": -114, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 416, + "top": 16, + "width": 519, + "height": 266, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk727jFxKQJwE=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk727jFxKVO34=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk727jGBKWuEs=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk727jGBKXsgE=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk727jGBKY7MM=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk728IaRLh+sU=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk728IaRLix2Y=", + "_parent": { + "$ref": "AAAAAAFk728IaRLh+sU=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk728IaRLjHZE=", + "_parent": { + "$ref": "AAAAAAFk728IaRLix2Y=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 101, + "top": 21, + "width": 199, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk728IaRLkooo=", + "_parent": { + "$ref": "AAAAAAFk728IaRLix2Y=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 101, + "top": 36, + "width": 199, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageManagerDelegate", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk728IaRLl5Ig=", + "_parent": { + "$ref": "AAAAAAFk728IaRLix2Y=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 101, + "top": 51, + "width": 199, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk728IahLmfNk=", + "_parent": { + "$ref": "AAAAAAFk728IaRLix2Y=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 62, + "top": -218, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 96, + "top": 16, + "width": 209, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk728IaRLjHZE=" + }, + "nameLabel": { + "$ref": "AAAAAAFk728IaRLkooo=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk728IaRLl5Ig=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk728IahLmfNk=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk728IahLnvPE=", + "_parent": { + "$ref": "AAAAAAFk728IaRLh+sU=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 31, + "top": -109, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk728IahLokSA=", + "_parent": { + "$ref": "AAAAAAFk728IaRLh+sU=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk728IeBMqyi8=", + "_parent": { + "$ref": "AAAAAAFk728IahLokSA=" + }, + "model": { + "$ref": "AAAAAAFUkh6LiI3wgxM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 101, + "top": 74, + "width": 223, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+shouldDownloadImageForURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk728IeRMtEUM=", + "_parent": { + "$ref": "AAAAAAFk728IahLokSA=" + }, + "model": { + "$ref": "AAAAAAFUkh65uI30vRk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 101, + "top": 89, + "width": 223, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+shouldBlockFailedURL()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 96, + "top": 69, + "width": 233, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk728IahLpEc4=", + "_parent": { + "$ref": "AAAAAAFk728IaRLh+sU=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 31, + "top": -109, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk728IahLqCYU=", + "_parent": { + "$ref": "AAAAAAFk728IaRLh+sU=" + }, + "model": { + "$ref": "AAAAAAFUkh5jeI3spbg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 31, + "top": -109, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 96, + "top": 16, + "width": 233, + "height": 102, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk728IaRLix2Y=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk728IahLnvPE=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk728IahLokSA=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk728IahLpEc4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk728IahLqCYU=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk728IbBLrg1w=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAIwc4=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk728IbBLsTIM=", + "_parent": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAIwc4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 372, + "top": 27, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk728IbBLtd0M=", + "_parent": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAIwc4=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 372, + "top": 12, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk728IbBLu2rg=", + "_parent": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAIwc4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 372, + "top": 57, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk728IbBLvCPg=", + "_parent": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAJw9E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 353, + "top": 27, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk728IbBLwavQ=", + "_parent": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAJw9E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 356, + "top": 13, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk728IbBLxNPQ=", + "_parent": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAJw9E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 349, + "top": 54, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk728IbBLy2kY=", + "_parent": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAKXzo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 390, + "top": 27, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk728IbBLzLUk=", + "_parent": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAKXzo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 387, + "top": 13, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk728IbBL0pIU=", + "_parent": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAKXzo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 394, + "top": 54, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk728IbRL1RgU=", + "_parent": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAJw9E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 80, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk728IbRL2GMQ=", + "_parent": { + "$ref": "AAAAAAFk728IbBLrg1w=" + }, + "model": { + "$ref": "AAAAAAFUmNGSiNAKXzo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 80, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk727jFxKPv/M=" + }, + "tail": { + "$ref": "AAAAAAFk728IaRLh+sU=" + }, + "lineStyle": 0, + "points": "328:48;416:48", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk728IbBLsTIM=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk728IbBLtd0M=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk728IbBLu2rg=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk728IbBLvCPg=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk728IbBLwavQ=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk728IbBLxNPQ=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk728IbBLy2kY=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk728IbBLzLUk=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk728IbBL0pIU=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk728IbRL1RgU=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk728IbRL2GMQ=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk73B3jhXY4fU=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73B3jhXZ0BQ=", + "_parent": { + "$ref": "AAAAAAFk73B3jhXY4fU=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73B3jhXaopQ=", + "_parent": { + "$ref": "AAAAAAFk73B3jhXZ0BQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 197, + "top": 349, + "width": 430, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73B3jhXb4Bg=", + "_parent": { + "$ref": "AAAAAAFk73B3jhXZ0BQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 197, + "top": 364, + "width": 430, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73B3jhXcvmw=", + "_parent": { + "$ref": "AAAAAAFk73B3jhXZ0BQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 197, + "top": 379, + "width": 430, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73B3jhXdWWc=", + "_parent": { + "$ref": "AAAAAAFk73B3jhXZ0BQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1016, + "top": -98, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 192, + "top": 344, + "width": 440, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73B3jhXaopQ=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73B3jhXb4Bg=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73B3jhXcvmw=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73B3jhXdWWc=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73B3jhXeph8=", + "_parent": { + "$ref": "AAAAAAFk73B3jhXY4fU=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -508, + "top": -49, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73B3jxXfo6w=", + "_parent": { + "$ref": "AAAAAAFk73B3jhXY4fU=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73B3lhYBDK0=", + "_parent": { + "$ref": "AAAAAAFk73B3jxXfo6w=" + }, + "model": { + "$ref": "AAAAAAFkzOhe6QsQ8iE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 197, + "top": 402, + "width": 454, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+queryImage(key, options, context, completionBlock): SDWebImageOperation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73B3lxYEmt4=", + "_parent": { + "$ref": "AAAAAAFk73B3jxXfo6w=" + }, + "model": { + "$ref": "AAAAAAFkzOmFQhJb/sw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 197, + "top": 417, + "width": 454, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+store(image, imageData, key, cacheType, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73B3lxYHgrM=", + "_parent": { + "$ref": "AAAAAAFk73B3jxXfo6w=" + }, + "model": { + "$ref": "AAAAAAFkzOpiQxehydI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 197, + "top": 432, + "width": 454, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeImage(key, cacheType, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73B3mBYKPcU=", + "_parent": { + "$ref": "AAAAAAFk73B3jxXfo6w=" + }, + "model": { + "$ref": "AAAAAAFkzOrxchsvmU0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 197, + "top": 447, + "width": 454, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+containsImage(key, cacheType, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73B3mBYNIJw=", + "_parent": { + "$ref": "AAAAAAFk73B3jxXfo6w=" + }, + "model": { + "$ref": "AAAAAAFkzOvaYx+Z2C8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 197, + "top": 462, + "width": 454, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+clear(cacheType, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 192, + "top": 397, + "width": 464, + "height": 83, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73B3jxXg5n0=", + "_parent": { + "$ref": "AAAAAAFk73B3jhXY4fU=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -508, + "top": -49, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73B3jxXhLf8=", + "_parent": { + "$ref": "AAAAAAFk73B3jhXY4fU=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -508, + "top": -49, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 192, + "top": 344, + "width": 464, + "height": 136, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73B3jhXZ0BQ=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73B3jhXeph8=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73B3jxXfo6w=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73B3jxXg5n0=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73B3jxXhLf8=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk73CEtxYgz34=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73CEuBYho/U=", + "_parent": { + "$ref": "AAAAAAFk73CEtxYgz34=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73CEuBYiTK8=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYho/U=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 349, + "width": 503, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73CEuBYjxQY=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYho/U=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 364, + "width": 503, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageLoader", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73CEuBYkZqc=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYho/U=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 379, + "width": 503, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73CEuBYlbTY=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYho/U=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 432, + "top": -140, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 664, + "top": 344, + "width": 513, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73CEuBYiTK8=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73CEuBYjxQY=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73CEuBYkZqc=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73CEuBYlbTY=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73CEuBYmeBU=", + "_parent": { + "$ref": "AAAAAAFk73CEtxYgz34=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 216, + "top": -70, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73CEuBYncWg=", + "_parent": { + "$ref": "AAAAAAFk73CEtxYgz34=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73CEwxZs26o=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYncWg=" + }, + "model": { + "$ref": "AAAAAAFky3AzTGhO/lc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 402, + "width": 527, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+canLoad(url): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73CEwxZv9Dc=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYncWg=" + }, + "model": { + "$ref": "AAAAAAFky3CxVms3ePA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 417, + "width": 527, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+loadImage(url, options, context, progressBlock, completedBlock): SDWebImageOperation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 664, + "top": 397, + "width": 537, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73CEuBYo8eM=", + "_parent": { + "$ref": "AAAAAAFk73CEtxYgz34=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 216, + "top": -70, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73CEuBYpu6E=", + "_parent": { + "$ref": "AAAAAAFk73CEtxYgz34=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 216, + "top": -70, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 664, + "top": 344, + "width": 537, + "height": 102, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73CEuBYho/U=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73CEuBYmeBU=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73CEuBYncWg=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73CEuBYo8eM=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73CEuBYpu6E=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk73CEuBYqAnI=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298aBP0=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73CEuRYrv4M=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298aBP0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 830, + "top": 305, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73CEuRYs5lE=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298aBP0=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 815, + "top": 305, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73CEuRYt8RY=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298aBP0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 859, + "top": 306, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73CEuRYus40=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298bVKc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 830, + "top": 312, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73CEuRYvZqU=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298bVKc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 816, + "top": 309, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73CEuRYw2ZU=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298bVKc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 857, + "top": 316, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73CEuRYx4RM=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298cZas=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 830, + "top": 300, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73CEuRYyyd0=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298cZas=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 816, + "top": 303, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73CEuRYzBn4=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298cZas=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 857, + "top": 296, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk73CEuRY0oAc=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298bVKc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 80, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk73CEuRY1lXY=", + "_parent": { + "$ref": "AAAAAAFk73CEuBYqAnI=" + }, + "model": { + "$ref": "AAAAAAFUmNjw298cZas=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 80, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk727jFxKPv/M=" + }, + "tail": { + "$ref": "AAAAAAFk73CEtxYgz34=" + }, + "lineStyle": 0, + "points": "845:344;845:281", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73CEuRYrv4M=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73CEuRYs5lE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73CEuRYt8RY=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk73CEuRYus40=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk73CEuRYvZqU=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk73CEuRYw2ZU=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk73CEuRYx4RM=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk73CEuRYyyd0=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk73CEuRYzBn4=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk73CEuRY0oAc=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk73CEuRY1lXY=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk73GNWBfUwoo=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk73GNVxfQMts=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73GNWBfVFvo=", + "_parent": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "model": { + "$ref": "AAAAAAFk73GNVxfQMts=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 569, + "top": 305, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73GNWBfWQPg=", + "_parent": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "model": { + "$ref": "AAAAAAFk73GNVxfQMts=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 554, + "top": 305, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73GNWRfXbGA=", + "_parent": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "model": { + "$ref": "AAAAAAFk73GNVxfQMts=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 598, + "top": 306, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73GNWRfYwn0=", + "_parent": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "model": { + "$ref": "AAAAAAFk73GNVxfRKkM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 569, + "top": 312, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73GNWRfZepQ=", + "_parent": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "model": { + "$ref": "AAAAAAFk73GNVxfRKkM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 555, + "top": 309, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73GNWRfatE4=", + "_parent": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "model": { + "$ref": "AAAAAAFk73GNVxfRKkM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 596, + "top": 316, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73GNWRfbFbs=", + "_parent": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "model": { + "$ref": "AAAAAAFk73GNVxfSppE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 569, + "top": 300, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73GNWRfcSyE=", + "_parent": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "model": { + "$ref": "AAAAAAFk73GNVxfSppE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 555, + "top": 303, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73GNWRfdpJA=", + "_parent": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "model": { + "$ref": "AAAAAAFk73GNVxfSppE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 596, + "top": 296, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk73GNWRfeX4I=", + "_parent": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "model": { + "$ref": "AAAAAAFk73GNVxfRKkM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 80, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk73GNWRffbCQ=", + "_parent": { + "$ref": "AAAAAAFk73GNWBfUwoo=" + }, + "model": { + "$ref": "AAAAAAFk73GNVxfSppE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 80, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk727jFxKPv/M=" + }, + "tail": { + "$ref": "AAAAAAFk73B3jhXY4fU=" + }, + "lineStyle": 0, + "points": "584:344;584:281", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73GNWBfVFvo=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73GNWBfWQPg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73GNWRfXbGA=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk73GNWRfYwn0=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk73GNWRfZepQ=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk73GNWRfatE4=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk73GNWRfbFbs=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk73GNWRfcSyE=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk73GNWRfdpJA=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk73GNWRfeX4I=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk73GNWRffbCQ=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk73Nn3x11ufk=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73Nn4B12s2E=", + "_parent": { + "$ref": "AAAAAAFk73Nn3x11ufk=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73Nn4B13Eps=", + "_parent": { + "$ref": "AAAAAAFk73Nn4B12s2E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -288, + "top": 2, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73Nn4B14O78=", + "_parent": { + "$ref": "AAAAAAFk73Nn4B12s2E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 551, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCachesManager", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73Nn4B15oY8=", + "_parent": { + "$ref": "AAAAAAFk73Nn4B12s2E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 566, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73Nn4B168Nc=", + "_parent": { + "$ref": "AAAAAAFk73Nn4B12s2E=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -288, + "top": 2, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 544, + "width": 210, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73Nn4B13Eps=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73Nn4B14O78=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73Nn4B15oY8=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73Nn4B168Nc=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73Nn4B17D4I=", + "_parent": { + "$ref": "AAAAAAFk73Nn3x11ufk=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73Nn8x2vCkE=", + "_parent": { + "$ref": "AAAAAAFk73Nn4B17D4I=" + }, + "model": { + "$ref": "AAAAAAFk7ALOcGXu/S8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 589, + "width": 200, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedManager", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73Nn9B2ypZU=", + "_parent": { + "$ref": "AAAAAAFk73Nn4B17D4I=" + }, + "model": { + "$ref": "AAAAAAFk7AOZr28Bcso=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 604, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+caches: Array ", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73Nn9B21pFU=", + "_parent": { + "$ref": "AAAAAAFk73Nn4B17D4I=" + }, + "model": { + "$ref": "AAAAAAFk7AMCg2fWSP0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 619, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+queryOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73Nn9B24euQ=", + "_parent": { + "$ref": "AAAAAAFk73Nn4B17D4I=" + }, + "model": { + "$ref": "AAAAAAFk7AMe/WlFG7c=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 634, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+storeOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73Nn9R2743k=", + "_parent": { + "$ref": "AAAAAAFk73Nn4B17D4I=" + }, + "model": { + "$ref": "AAAAAAFk7ANGZ2q0x2Q=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 649, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73Nn9R2+HdA=", + "_parent": { + "$ref": "AAAAAAFk73Nn4B17D4I=" + }, + "model": { + "$ref": "AAAAAAFk7ANfz2wjKJg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 664, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+containsOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73Nn9h3BTMc=", + "_parent": { + "$ref": "AAAAAAFk73Nn4B17D4I=" + }, + "model": { + "$ref": "AAAAAAFk7AN7JG2S4JE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 679, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+clearOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 584, + "width": 210, + "height": 113, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73Nn4R18MWk=", + "_parent": { + "$ref": "AAAAAAFk73Nn3x11ufk=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73Nn9h3ELAk=", + "_parent": { + "$ref": "AAAAAAFk73Nn4R18MWk=" + }, + "model": { + "$ref": "AAAAAAFk7AQw/nZyZkk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 702, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+addCache()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73Nn9x3HaEk=", + "_parent": { + "$ref": "AAAAAAFk73Nn4R18MWk=" + }, + "model": { + "$ref": "AAAAAAFk7ARL1nfhIfg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 717, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeCache()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 697, + "width": 210, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73Nn4R193Bw=", + "_parent": { + "$ref": "AAAAAAFk73Nn3x11ufk=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -144, + "top": 1, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73Nn4R1+OGI=", + "_parent": { + "$ref": "AAAAAAFk73Nn3x11ufk=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -144, + "top": 1, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 16, + "top": 544, + "width": 210, + "height": 191, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73Nn4B12s2E=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73Nn4B17D4I=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73Nn4R18MWk=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73Nn4R193Bw=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73Nn4R1+OGI=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk73Nn4x1/yIE=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk7Ae0KaF0uoo=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73Nn5B2Az5k=", + "_parent": { + "$ref": "AAAAAAFk73Nn4x1/yIE=" + }, + "model": { + "$ref": "AAAAAAFk7Ae0KaF0uoo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 160, + "top": 427, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73Nn4x1/yIE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73Nn5B2BT+A=", + "_parent": { + "$ref": "AAAAAAFk73Nn4x1/yIE=" + }, + "model": { + "$ref": "AAAAAAFk7Ae0KaF0uoo=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 160, + "top": 412, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73Nn4x1/yIE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73Nn5B2CncI=", + "_parent": { + "$ref": "AAAAAAFk73Nn4x1/yIE=" + }, + "model": { + "$ref": "AAAAAAFk7Ae0KaF0uoo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 160, + "top": 457, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73Nn4x1/yIE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73B3jhXY4fU=" + }, + "tail": { + "$ref": "AAAAAAFk73Nn3x11ufk=" + }, + "lineStyle": 0, + "points": "160:544;160:448;192:448", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73Nn5B2Az5k=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73Nn5B2BT+A=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73Nn5B2CncI=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk73N95h37fUo=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73N95h38H7I=", + "_parent": { + "$ref": "AAAAAAFk73N95h37fUo=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73N95h39g2E=", + "_parent": { + "$ref": "AAAAAAFk73N95h38H7I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -560, + "top": -126, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73N95h3+t5c=", + "_parent": { + "$ref": "AAAAAAFk73N95h38H7I=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 551, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73N95h3/ldg=", + "_parent": { + "$ref": "AAAAAAFk73N95h38H7I=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 566, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73N95x4A4gg=", + "_parent": { + "$ref": "AAAAAAFk73N95h38H7I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -560, + "top": -126, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 232, + "top": 544, + "width": 424, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73N95h39g2E=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73N95h3+t5c=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73N95h3/ldg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73N95x4A4gg=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73N95x4BBs8=", + "_parent": { + "$ref": "AAAAAAFk73N95h37fUo=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73N9+R5Y/rE=", + "_parent": { + "$ref": "AAAAAAFk73N95x4BBs8=" + }, + "model": { + "$ref": "AAAAAAFUkiFzJY5gThM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 589, + "width": 414, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedImageCache", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73N9+R5bmiY=", + "_parent": { + "$ref": "AAAAAAFk73N95x4BBs8=" + }, + "model": { + "$ref": "AAAAAAFk0LaA7lthFIA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 604, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+config: SDImageCacheConfig", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73N9+R5e0Ls=", + "_parent": { + "$ref": "AAAAAAFk73N95x4BBs8=" + }, + "model": { + "$ref": "AAAAAAFUmPDC7hpSvPQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 619, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+diskCachePath", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73N9+h5hivg=", + "_parent": { + "$ref": "AAAAAAFk73N95x4BBs8=" + }, + "model": { + "$ref": "AAAAAAFUmPDhrRsNyCc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 634, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+additionalCachePathBlock", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 232, + "top": 584, + "width": 424, + "height": 68, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73N95x4CPHU=", + "_parent": { + "$ref": "AAAAAAFk73N95h37fUo=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N9+h5kCpU=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFUmPHYnB7PNs4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 657, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(namespace, diskCacheDirectory, config)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N9+h5nCHw=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFUmPTT0CgBzK8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 672, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cachePath(key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N9+x5qlQU=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFUmPMOWiHsOa0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 687, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+store(image, imageData, key, toDisk, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N9+x5tWas=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFUmPMtQiKnVfM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 702, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+storeImage(image, key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N9/B5wdZ0=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFk0NC0bOZw4VQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 717, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+storeImageData(imageData, key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N9/B5zoyE=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFk0NF3Z+sY0tc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 732, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+diskImageExists(key, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N9/B529nU=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFk0NJKG+/90EA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 747, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+diskImageDataExists(key): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N9/R55E3k=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFk0NLcpfVc3Q8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 762, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+diskImageData(key): Data", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N9/R58wJs=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFk0NOWwPpBKis=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 777, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+queryCacheOperation(key, options, context, doneBlock): NSOperation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N9/R5/gk4=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFUmPOk0iRaSME=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 792, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageFromMemoryCache(key): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N9/h6C8GQ=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFUmPPBiSUVHSU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 807, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageFromDiskCache(key): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N9/h6Fs0w=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFk0NaQzAru2sk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 822, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageFromCache(key): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N9/h6IKmY=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFUmPPiwSXQs7U=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 837, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeImage(key, fromDisk, completion)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N9/x6L7OY=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFk0NfB0BJxwa0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 852, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeImageFromMemory(key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N+AB6ORPo=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFk0NhSwxdz+po=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 867, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeImageFromDisk(key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N+AB6RA0I=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFUmPQzYSaLCQc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 882, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+clearMemory()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N+AB6UN34=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFUmPRYYSdGCZA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 897, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+clearDIsk(completion)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N+AR6XtE8=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFUmPT4WSi8pg0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 912, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+deleteOldFiles(completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N+Ah6a0Eg=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFk0Nk9Zhzuux0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 927, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+getSize(): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N+Ah6doBs=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFk0NmTbx80+MQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 942, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+getDiskCount(): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73N+Ah6gsjw=", + "_parent": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "model": { + "$ref": "AAAAAAFk0Nn28SF6Hq4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 237, + "top": 957, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+calculateSize(completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 232, + "top": 652, + "width": 424, + "height": 323, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73N95x4DXTs=", + "_parent": { + "$ref": "AAAAAAFk73N95h37fUo=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -280, + "top": -63, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73N95x4EwTY=", + "_parent": { + "$ref": "AAAAAAFk73N95h37fUo=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -280, + "top": -63, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 232, + "top": 544, + "width": 424, + "height": 431, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73N95h38H7I=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73N95x4BBs8=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73N95x4CPHU=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73N95x4DXTs=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73N95x4EwTY=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk73N96R4FSXQ=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73N96R4GNtM=", + "_parent": { + "$ref": "AAAAAAFk73N96R4FSXQ=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 414, + "top": 504, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73N96R4FSXQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73N96R4HX24=", + "_parent": { + "$ref": "AAAAAAFk73N96R4FSXQ=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 399, + "top": 504, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73N96R4FSXQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73N96R4Iufc=", + "_parent": { + "$ref": "AAAAAAFk73N96R4FSXQ=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 443, + "top": 505, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73N96R4FSXQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73B3jhXY4fU=" + }, + "tail": { + "$ref": "AAAAAAFk73N95h37fUo=" + }, + "lineStyle": 0, + "points": "429:544;429:479", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73N96R4GNtM=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73N96R4HX24=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73N96R4Iufc=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk73VlvSqddMs=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73Vlviqe0Hc=", + "_parent": { + "$ref": "AAAAAAFk73VlvSqddMs=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73VlviqfHqc=", + "_parent": { + "$ref": "AAAAAAFk73Vlviqe0Hc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -276, + "top": -82, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73VlviqgKGc=", + "_parent": { + "$ref": "AAAAAAFk73Vlviqe0Hc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 551, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloader", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73Vlviqh6JM=", + "_parent": { + "$ref": "AAAAAAFk73Vlviqe0Hc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 566, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73Vlviqi7/Y=", + "_parent": { + "$ref": "AAAAAAFk73Vlviqe0Hc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -276, + "top": -82, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 664, + "top": 544, + "width": 523, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73VlviqfHqc=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73VlviqgKGc=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73Vlviqh6JM=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73Vlviqi7/Y=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73VlviqjZw4=", + "_parent": { + "$ref": "AAAAAAFk73VlvSqddMs=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73Vlzirvd8g=", + "_parent": { + "$ref": "AAAAAAFk73VlviqjZw4=" + }, + "model": { + "$ref": "AAAAAAFUkiJAhI5kL78=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 589, + "width": 513, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedDownloader", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73VlziryyUg=", + "_parent": { + "$ref": "AAAAAAFk73VlviqjZw4=" + }, + "model": { + "$ref": "AAAAAAFUmOMr1ewzvaI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 604, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+config: SDWebImageDownloaderConfig", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73Vlzyr1+EU=", + "_parent": { + "$ref": "AAAAAAFk73VlviqjZw4=" + }, + "model": { + "$ref": "AAAAAAFUmONDtOzuN2c=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 619, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+requestModifier: SDWebImageDownloaderRequestModifier", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73Vlzyr4oXI=", + "_parent": { + "$ref": "AAAAAAFk73VlviqjZw4=" + }, + "model": { + "$ref": "AAAAAAFUmOaPcvo7CuM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 634, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sessionConfiguration", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73Vlzyr7WCM=", + "_parent": { + "$ref": "AAAAAAFk73VlviqjZw4=" + }, + "model": { + "$ref": "AAAAAAFUmOa7+/r2ysU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 649, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+suspended", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73Vl0Cr+uls=", + "_parent": { + "$ref": "AAAAAAFk73VlviqjZw4=" + }, + "model": { + "$ref": "AAAAAAFUmOiCz/5aGv0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 664, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+currentDownloadCount", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 664, + "top": 584, + "width": 523, + "height": 98, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73VlviqkMTY=", + "_parent": { + "$ref": "AAAAAAFk73VlvSqddMs=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73Vl0CsBbI4=", + "_parent": { + "$ref": "AAAAAAFk73VlviqkMTY=" + }, + "model": { + "$ref": "AAAAAAFXmuCdynfN50Y=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 687, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(config)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73Vl0SsE8p4=", + "_parent": { + "$ref": "AAAAAAFk73VlviqkMTY=" + }, + "model": { + "$ref": "AAAAAAFUmOeh6PwLtkk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 702, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+setValue(value, HTTPHeaderField)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73Vl0SsHh6w=", + "_parent": { + "$ref": "AAAAAAFk73VlviqkMTY=" + }, + "model": { + "$ref": "AAAAAAFky3dFIIXZ21M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 717, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+value(HTTPHeaderField): String", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73Vl0SsKZUs=", + "_parent": { + "$ref": "AAAAAAFk73VlviqkMTY=" + }, + "model": { + "$ref": "AAAAAAFUmOOite2pkfo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 732, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+downloadImage(url, options, context, progressBlock, completedBlock): DownloadToken", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73Vl0isNVBE=", + "_parent": { + "$ref": "AAAAAAFk73VlviqkMTY=" + }, + "model": { + "$ref": "AAAAAAFUmOgcH/2BRjw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 747, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cancelAllDownloads()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73Vl0isQFVw=", + "_parent": { + "$ref": "AAAAAAFk73VlviqkMTY=" + }, + "model": { + "$ref": "AAAAAAFUmOZtsvmAcFQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 669, + "top": 762, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+invalidateSessionAndCancel()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 664, + "top": 682, + "width": 523, + "height": 98, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73VlviqlvDI=", + "_parent": { + "$ref": "AAAAAAFk73VlvSqddMs=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -138, + "top": -41, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73VlviqmOqo=", + "_parent": { + "$ref": "AAAAAAFk73VlvSqddMs=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -138, + "top": -41, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 664, + "top": 544, + "width": 523, + "height": 236, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73Vlviqe0Hc=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73VlviqjZw4=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73VlviqkMTY=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73VlviqlvDI=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73VlviqmOqo=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk73Wx7ywgOSI=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk73Wx7ywf4cU=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73Wx7ywhUtU=", + "_parent": { + "$ref": "AAAAAAFk73Wx7ywgOSI=" + }, + "model": { + "$ref": "AAAAAAFk73Wx7ywf4cU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 905, + "top": 487, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73Wx7ywgOSI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73Wx7ywihaM=", + "_parent": { + "$ref": "AAAAAAFk73Wx7ywgOSI=" + }, + "model": { + "$ref": "AAAAAAFk73Wx7ywf4cU=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 890, + "top": 487, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73Wx7ywgOSI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73Wx7ywj7ts=", + "_parent": { + "$ref": "AAAAAAFk73Wx7ywgOSI=" + }, + "model": { + "$ref": "AAAAAAFk73Wx7ywf4cU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 934, + "top": 488, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73Wx7ywgOSI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73CEtxYgz34=" + }, + "tail": { + "$ref": "AAAAAAFk73VlvSqddMs=" + }, + "lineStyle": 0, + "points": "920:544;920:445", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73Wx7ywhUtU=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73Wx7ywihaM=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73Wx7ywj7ts=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk73ZHwS8Q8A8=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73ZHwS8RThg=", + "_parent": { + "$ref": "AAAAAAFk73ZHwS8Q8A8=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73ZHwS8Sggc=", + "_parent": { + "$ref": "AAAAAAFk73ZHwS8RThg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -216, + "top": -26, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73ZHwS8TS20=", + "_parent": { + "$ref": "AAAAAAFk73ZHwS8RThg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1197, + "top": 551, + "width": 202, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageLoadersManager", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73ZHwS8U844=", + "_parent": { + "$ref": "AAAAAAFk73ZHwS8RThg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1197, + "top": 566, + "width": 202, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73ZHwS8Vv9U=", + "_parent": { + "$ref": "AAAAAAFk73ZHwS8RThg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -216, + "top": -26, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1192, + "top": 544, + "width": 212, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73ZHwS8Sggc=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73ZHwS8TS20=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73ZHwS8U844=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73ZHwS8Vv9U=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73ZHwS8WBp0=", + "_parent": { + "$ref": "AAAAAAFk73ZHwS8Q8A8=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73ZHzi9KTVY=", + "_parent": { + "$ref": "AAAAAAFk73ZHwS8WBp0=" + }, + "model": { + "$ref": "AAAAAAFkzOIg/+78rRg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1197, + "top": 589, + "width": 202, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedManager", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73ZHzy9N37U=", + "_parent": { + "$ref": "AAAAAAFk73ZHwS8WBp0=" + }, + "model": { + "$ref": "AAAAAAFkzOOPjva3FJM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1197, + "top": 604, + "width": 202, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+loaders: Array ", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1192, + "top": 584, + "width": 212, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73ZHwS8XQfo=", + "_parent": { + "$ref": "AAAAAAFk73ZHwS8Q8A8=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73ZHzy9Qlok=", + "_parent": { + "$ref": "AAAAAAFk73ZHwS8XQfo=" + }, + "model": { + "$ref": "AAAAAAFkzOP6yPhv64w=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1197, + "top": 627, + "width": 202, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+addLoader()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73ZH0C9TOi0=", + "_parent": { + "$ref": "AAAAAAFk73ZHwS8XQfo=" + }, + "model": { + "$ref": "AAAAAAFkzOQxGfm6yKY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1197, + "top": 642, + "width": 202, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeLoader()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1192, + "top": 622, + "width": 212, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73ZHwi8YV5I=", + "_parent": { + "$ref": "AAAAAAFk73ZHwS8Q8A8=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -108, + "top": -13, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73ZHwi8Zvrc=", + "_parent": { + "$ref": "AAAAAAFk73ZHwS8Q8A8=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -108, + "top": -13, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1192, + "top": 544, + "width": 212, + "height": 116, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73ZHwS8RThg=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73ZHwS8WBp0=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73ZHwS8XQfo=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73ZHwi8YV5I=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73ZHwi8Zvrc=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk73ZHwi8aHME=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk7AFZvlix+G0=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73ZHwy8boU4=", + "_parent": { + "$ref": "AAAAAAFk73ZHwi8aHME=" + }, + "model": { + "$ref": "AAAAAAFk7AFZvlix+G0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1247, + "top": 433, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73ZHwi8aHME=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73ZHwy8cyJI=", + "_parent": { + "$ref": "AAAAAAFk73ZHwi8aHME=" + }, + "model": { + "$ref": "AAAAAAFk7AFZvlix+G0=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1247, + "top": 448, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73ZHwi8aHME=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73ZHwy8dqks=", + "_parent": { + "$ref": "AAAAAAFk73ZHwi8aHME=" + }, + "model": { + "$ref": "AAAAAAFk7AFZvlix+G0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1248, + "top": 403, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73ZHwi8aHME=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73CEtxYgz34=" + }, + "tail": { + "$ref": "AAAAAAFk73ZHwS8Q8A8=" + }, + "lineStyle": 0, + "points": "1248:544;1248:424;1200:424", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73ZHwy8boU4=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73ZHwy8cyJI=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73ZHwy8dqks=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk73ctFDKmdZw=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73ctFTKn/Qs=", + "_parent": { + "$ref": "AAAAAAFk73ctFDKmdZw=" + }, + "model": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73ctFTKoDvU=", + "_parent": { + "$ref": "AAAAAAFk73ctFTKn/Qs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1045, + "top": 37, + "width": 218, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73ctFTKp5GM=", + "_parent": { + "$ref": "AAAAAAFk73ctFTKn/Qs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1045, + "top": 52, + "width": 218, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageTransformer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73ctFTKqAq4=", + "_parent": { + "$ref": "AAAAAAFk73ctFTKn/Qs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1045, + "top": 67, + "width": 218, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage - Transformers)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73ctFTKrhZw=", + "_parent": { + "$ref": "AAAAAAFk73ctFTKn/Qs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 90, + "top": -152, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1040, + "top": 32, + "width": 228, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73ctFTKoDvU=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73ctFTKp5GM=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73ctFTKqAq4=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73ctFTKrhZw=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73ctFTKs5Ns=", + "_parent": { + "$ref": "AAAAAAFk73ctFDKmdZw=" + }, + "model": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 45, + "top": -76, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73ctFTKtmTs=", + "_parent": { + "$ref": "AAAAAAFk73ctFDKmdZw=" + }, + "model": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73ctIjLVdcg=", + "_parent": { + "$ref": "AAAAAAFk73ctFTKtmTs=" + }, + "model": { + "$ref": "AAAAAAFk7BJFY/NyunQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1045, + "top": 90, + "width": 242, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+transformerKey(): String", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73ctIjLYM+E=", + "_parent": { + "$ref": "AAAAAAFk73ctFTKtmTs=" + }, + "model": { + "$ref": "AAAAAAFk7BKJjfW40dE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1045, + "top": 105, + "width": 242, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+transformedImage(image, key): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1040, + "top": 85, + "width": 252, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73ctFTKurCo=", + "_parent": { + "$ref": "AAAAAAFk73ctFDKmdZw=" + }, + "model": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 45, + "top": -76, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73ctFjKvDKM=", + "_parent": { + "$ref": "AAAAAAFk73ctFDKmdZw=" + }, + "model": { + "$ref": "AAAAAAFk7BHRjPCnfdg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 45, + "top": -76, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1040, + "top": 32, + "width": 252, + "height": 102, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73ctFTKn/Qs=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73ctFTKs5Ns=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73ctFTKtmTs=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73ctFTKurCo=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73ctFjKvDKM=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk73edDjUN4ZE=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73edDjUOwxY=", + "_parent": { + "$ref": "AAAAAAFk73edDjUN4ZE=" + }, + "model": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73edDjUPRDo=", + "_parent": { + "$ref": "AAAAAAFk73edDjUOwxY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -32, + "top": -56, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73edDjUQJl8=", + "_parent": { + "$ref": "AAAAAAFk73edDjUOwxY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 39, + "width": 264, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImagePipelineTransformer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73edDjUR9gU=", + "_parent": { + "$ref": "AAAAAAFk73edDjUOwxY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 54, + "width": 264, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage - Transformers)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73edDjUSpZc=", + "_parent": { + "$ref": "AAAAAAFk73edDjUOwxY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -32, + "top": -56, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1392, + "top": 32, + "width": 274, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73edDjUPRDo=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73edDjUQJl8=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73edDjUR9gU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73edDjUSpZc=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73edDjUT488=", + "_parent": { + "$ref": "AAAAAAFk73edDjUN4ZE=" + }, + "model": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73edHDVHok8=", + "_parent": { + "$ref": "AAAAAAFk73edDjUT488=" + }, + "model": { + "$ref": "AAAAAAFk7BQPCv5irlw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 77, + "width": 264, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+transformers: Array ", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1392, + "top": 72, + "width": 274, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73edDjUU6Jo=", + "_parent": { + "$ref": "AAAAAAFk73edDjUN4ZE=" + }, + "model": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73edHDVKU9s=", + "_parent": { + "$ref": "AAAAAAFk73edDjUU6Jo=" + }, + "model": { + "$ref": "AAAAAAFk7BRdnQBKmBE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 100, + "width": 264, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(transformers)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1392, + "top": 95, + "width": 274, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73edDzUVF94=", + "_parent": { + "$ref": "AAAAAAFk73edDjUN4ZE=" + }, + "model": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -16, + "top": -28, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73edDzUW3fk=", + "_parent": { + "$ref": "AAAAAAFk73edDjUN4ZE=" + }, + "model": { + "$ref": "AAAAAAFk7BNlf/pTkyo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -16, + "top": -28, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1392, + "top": 32, + "width": 274, + "height": 86, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73edDjUOwxY=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73edDjUT488=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73edDjUU6Jo=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73edDzUVF94=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73edDzUW3fk=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk73edDzUXMQA=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk7BOsyPu6CB8=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73edDzUYzuQ=", + "_parent": { + "$ref": "AAAAAAFk73edDzUXMQA=" + }, + "model": { + "$ref": "AAAAAAFk7BOsyPu6CB8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1340, + "top": 88, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73edDzUXMQA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73edDzUZrg0=", + "_parent": { + "$ref": "AAAAAAFk73edDzUXMQA=" + }, + "model": { + "$ref": "AAAAAAFk7BOsyPu6CB8=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1340, + "top": 103, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73edDzUXMQA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73edDzUax5w=", + "_parent": { + "$ref": "AAAAAAFk73edDzUXMQA=" + }, + "model": { + "$ref": "AAAAAAFk7BOsyPu6CB8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1341, + "top": 58, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73edDzUXMQA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73ctFDKmdZw=" + }, + "tail": { + "$ref": "AAAAAAFk73edDjUN4ZE=" + }, + "lineStyle": 0, + "points": "1392:79;1291:79", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73edDzUYzuQ=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73edDzUZrg0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73edDzUax5w=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk73ggjzeeklY=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk73ggjzeamEo=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73ggjzefZ34=", + "_parent": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "model": { + "$ref": "AAAAAAFk73ggjzeamEo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 986, + "top": 81, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73ggjzegUYs=", + "_parent": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "model": { + "$ref": "AAAAAAFk73ggjzeamEo=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 986, + "top": 96, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73ggjzehj4Y=", + "_parent": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "model": { + "$ref": "AAAAAAFk73ggjzeamEo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 987, + "top": 51, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73ggjzeiooI=", + "_parent": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "model": { + "$ref": "AAAAAAFk73ggjzebOxM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1014, + "top": 80, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73ggjzejyUY=", + "_parent": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "model": { + "$ref": "AAAAAAFk73ggjzebOxM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1011, + "top": 94, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73ggjzek2tU=", + "_parent": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "model": { + "$ref": "AAAAAAFk73ggjzebOxM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1018, + "top": 53, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73ggjzelNdM=", + "_parent": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "model": { + "$ref": "AAAAAAFk73ggjzec0ak=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 959, + "top": 80, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73ggjzemJvc=", + "_parent": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "model": { + "$ref": "AAAAAAFk73ggjzec0ak=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 962, + "top": 94, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73ggjzenU5k=", + "_parent": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "model": { + "$ref": "AAAAAAFk73ggjzec0ak=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 955, + "top": 53, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk73ggjzeoJtY=", + "_parent": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "model": { + "$ref": "AAAAAAFk73ggjzebOxM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk73ggjzepKGU=", + "_parent": { + "$ref": "AAAAAAFk73ggjzeeklY=" + }, + "model": { + "$ref": "AAAAAAFk73ggjzec0ak=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk727jFxKPv/M=" + }, + "tail": { + "$ref": "AAAAAAFk73ctFDKmdZw=" + }, + "lineStyle": 0, + "points": "1040:72;934:72", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73ggjzefZ34=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73ggjzegUYs=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73ggjzehj4Y=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk73ggjzeiooI=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk73ggjzejyUY=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk73ggjzek2tU=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk73ggjzelNdM=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk73ggjzemJvc=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk73ggjzenU5k=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk73ggjzeoJtY=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk73ggjzepKGU=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk73h74TjND7o=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73h74TjOnME=", + "_parent": { + "$ref": "AAAAAAFk73h74TjND7o=" + }, + "model": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73h74TjP8IM=", + "_parent": { + "$ref": "AAAAAAFk73h74TjOnME=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1045, + "top": 237, + "width": 186, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73h74TjQolc=", + "_parent": { + "$ref": "AAAAAAFk73h74TjOnME=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1045, + "top": 252, + "width": 186, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageCacheKeyFilter", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73h74TjR5wY=", + "_parent": { + "$ref": "AAAAAAFk73h74TjOnME=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1045, + "top": 267, + "width": 186, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73h74TjSYIk=", + "_parent": { + "$ref": "AAAAAAFk73h74TjOnME=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -202, + "top": 50, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1040, + "top": 232, + "width": 196, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73h74TjP8IM=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73h74TjQolc=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73h74TjR5wY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73h74TjSYIk=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73h74TjT01M=", + "_parent": { + "$ref": "AAAAAAFk73h74TjND7o=" + }, + "model": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -101, + "top": 25, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73h74TjUMl0=", + "_parent": { + "$ref": "AAAAAAFk73h74TjND7o=" + }, + "model": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73h77zj/kA4=", + "_parent": { + "$ref": "AAAAAAFk73h74TjUMl0=" + }, + "model": { + "$ref": "AAAAAAFk7AyMbdSMtVQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1045, + "top": 290, + "width": 210, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cacheKey(url): String", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1040, + "top": 285, + "width": 220, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73h74jjVGyk=", + "_parent": { + "$ref": "AAAAAAFk73h74TjND7o=" + }, + "model": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -101, + "top": 25, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73h74jjWt5Q=", + "_parent": { + "$ref": "AAAAAAFk73h74TjND7o=" + }, + "model": { + "$ref": "AAAAAAFk7AwM/dC2p54=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -101, + "top": 25, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1040, + "top": 232, + "width": 220, + "height": 76, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73h74TjOnME=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73h74TjT01M=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73h74TjUMl0=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73h74jjVGyk=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73h74jjWt5Q=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk73iEuTk/DXw=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73iEuTlAwyQ=", + "_parent": { + "$ref": "AAAAAAFk73iEuTk/DXw=" + }, + "model": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73iEujlB8GY=", + "_parent": { + "$ref": "AAAAAAFk73iEuTlAwyQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1045, + "top": 149, + "width": 225, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73iEujlClw4=", + "_parent": { + "$ref": "AAAAAAFk73iEuTlAwyQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1045, + "top": 164, + "width": 225, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageCacheSerializer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73iEujlDYVU=", + "_parent": { + "$ref": "AAAAAAFk73iEuTlAwyQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1045, + "top": 179, + "width": 225, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73iEujlEnlM=", + "_parent": { + "$ref": "AAAAAAFk73iEuTlAwyQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -556, + "top": -320, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1040, + "top": 144, + "width": 235, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73iEujlB8GY=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73iEujlClw4=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73iEujlDYVU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73iEujlEnlM=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73iEujlFHZY=", + "_parent": { + "$ref": "AAAAAAFk73iEuTk/DXw=" + }, + "model": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -278, + "top": -160, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73iEujlG+/s=", + "_parent": { + "$ref": "AAAAAAFk73iEuTk/DXw=" + }, + "model": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73iExjlxfeE=", + "_parent": { + "$ref": "AAAAAAFk73iEujlG+/s=" + }, + "model": { + "$ref": "AAAAAAFk7A8qouQCrJM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1045, + "top": 202, + "width": 249, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cacheData(image, data, imageURL): Data", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1040, + "top": 197, + "width": 259, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73iEujlHH1o=", + "_parent": { + "$ref": "AAAAAAFk73iEuTk/DXw=" + }, + "model": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -278, + "top": -160, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73iEujlIHVw=", + "_parent": { + "$ref": "AAAAAAFk73iEuTk/DXw=" + }, + "model": { + "$ref": "AAAAAAFk7A6KJuCHZbI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -278, + "top": -160, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1040, + "top": 144, + "width": 259, + "height": 76, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73iEuTlAwyQ=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73iEujlFHZY=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73iEujlG+/s=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73iEujlHH1o=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73iEujlIHVw=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk73j1jDxl0M4=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk73j1izxh7DI=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73j1jTxmcpY=", + "_parent": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "model": { + "$ref": "AAAAAAFk73j1izxh7DI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 986, + "top": 181, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73j1jTxnPw4=", + "_parent": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "model": { + "$ref": "AAAAAAFk73j1izxh7DI=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 986, + "top": 196, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73j1jTxo5kE=", + "_parent": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "model": { + "$ref": "AAAAAAFk73j1izxh7DI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 987, + "top": 151, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73j1jTxpVzU=", + "_parent": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "model": { + "$ref": "AAAAAAFk73j1jDxidxA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1014, + "top": 180, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73j1jTxq/kg=", + "_parent": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "model": { + "$ref": "AAAAAAFk73j1jDxidxA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1011, + "top": 194, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73j1jTxraZg=", + "_parent": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "model": { + "$ref": "AAAAAAFk73j1jDxidxA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1018, + "top": 153, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73j1jTxscX4=", + "_parent": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "model": { + "$ref": "AAAAAAFk73j1jDxjzus=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 959, + "top": 180, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73j1jTxtEC8=", + "_parent": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "model": { + "$ref": "AAAAAAFk73j1jDxjzus=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 962, + "top": 194, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73j1jTxuSnQ=", + "_parent": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "model": { + "$ref": "AAAAAAFk73j1jDxjzus=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 955, + "top": 153, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk73j1jTxvZnc=", + "_parent": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "model": { + "$ref": "AAAAAAFk73j1jDxidxA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk73j1jjxw6Nk=", + "_parent": { + "$ref": "AAAAAAFk73j1jDxl0M4=" + }, + "model": { + "$ref": "AAAAAAFk73j1jDxjzus=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk727jFxKPv/M=" + }, + "tail": { + "$ref": "AAAAAAFk73iEuTk/DXw=" + }, + "lineStyle": 0, + "points": "1040:172;934:172", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73j1jTxmcpY=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73j1jTxnPw4=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73j1jTxo5kE=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk73j1jTxpVzU=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk73j1jTxq/kg=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk73j1jTxraZg=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk73j1jTxscX4=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk73j1jTxtEC8=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk73j1jTxuSnQ=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk73j1jTxvZnc=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk73j1jjxw6Nk=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk73kBwz0CWOc=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk73kBwjz+9fY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73kBwz0D7k8=", + "_parent": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "model": { + "$ref": "AAAAAAFk73kBwjz+9fY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 986, + "top": 257, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73kBwz0ETbg=", + "_parent": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "model": { + "$ref": "AAAAAAFk73kBwjz+9fY=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 986, + "top": 272, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73kBwz0FvSo=", + "_parent": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "model": { + "$ref": "AAAAAAFk73kBwjz+9fY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 987, + "top": 227, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73kBwz0GaJU=", + "_parent": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "model": { + "$ref": "AAAAAAFk73kBwjz/iCg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1014, + "top": 256, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73kBxD0HKDM=", + "_parent": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "model": { + "$ref": "AAAAAAFk73kBwjz/iCg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1011, + "top": 270, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73kBxD0IfXw=", + "_parent": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "model": { + "$ref": "AAAAAAFk73kBwjz/iCg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1018, + "top": 229, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73kBxD0J+zE=", + "_parent": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "model": { + "$ref": "AAAAAAFk73kBwj0A87w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 959, + "top": 256, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73kBxD0K540=", + "_parent": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "model": { + "$ref": "AAAAAAFk73kBwj0A87w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 962, + "top": 270, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73kBxD0LHXY=", + "_parent": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "model": { + "$ref": "AAAAAAFk73kBwj0A87w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 955, + "top": 229, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk73kBxD0MJEY=", + "_parent": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "model": { + "$ref": "AAAAAAFk73kBwjz/iCg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk73kBxD0NML0=", + "_parent": { + "$ref": "AAAAAAFk73kBwz0CWOc=" + }, + "model": { + "$ref": "AAAAAAFk73kBwj0A87w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk727jFxKPv/M=" + }, + "tail": { + "$ref": "AAAAAAFk73h74TjND7o=" + }, + "lineStyle": 0, + "points": "1040:248;934:248", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73kBwz0D7k8=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73kBwz0ETbg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73kBwz0FvSo=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk73kBwz0GaJU=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk73kBxD0HKDM=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk73kBxD0IfXw=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk73kBxD0J+zE=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk73kBxD0K540=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk73kBxD0LHXY=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk73kBxD0MJEY=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk73kBxD0NML0=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk73lGFD9Ae88=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk7Aze6dcrc1c=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73lGFT9BYnA=", + "_parent": { + "$ref": "AAAAAAFk73lGFD9Ae88=" + }, + "model": { + "$ref": "AAAAAAFk7Aze6dcrc1c=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73lGFT9CfvU=", + "_parent": { + "$ref": "AAAAAAFk73lGFT9BYnA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -240, + "top": -84, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73lGFT9DKUc=", + "_parent": { + "$ref": "AAAAAAFk73lGFT9BYnA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 239, + "width": 176, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageCacheKeyFilter", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73lGFT9EeE0=", + "_parent": { + "$ref": "AAAAAAFk73lGFT9BYnA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 254, + "width": 176, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73lGFT9F+68=", + "_parent": { + "$ref": "AAAAAAFk73lGFT9BYnA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -240, + "top": -84, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1392, + "top": 232, + "width": 186, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73lGFT9CfvU=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73lGFT9DKUc=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73lGFT9EeE0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73lGFT9F+68=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73lGFT9GB9k=", + "_parent": { + "$ref": "AAAAAAFk73lGFD9Ae88=" + }, + "model": { + "$ref": "AAAAAAFk7Aze6dcrc1c=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1392, + "top": 272, + "width": 186, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73lGFT9HbmY=", + "_parent": { + "$ref": "AAAAAAFk73lGFD9Ae88=" + }, + "model": { + "$ref": "AAAAAAFk7Aze6dcrc1c=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73lGJz+DPDI=", + "_parent": { + "$ref": "AAAAAAFk73lGFT9HbmY=" + }, + "model": { + "$ref": "AAAAAAFk7A2zWNuPpjU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 287, + "width": 176, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(block)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1392, + "top": 282, + "width": 186, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73lGFj9IINY=", + "_parent": { + "$ref": "AAAAAAFk73lGFD9Ae88=" + }, + "model": { + "$ref": "AAAAAAFk7Aze6dcrc1c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -120, + "top": -42, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73lGFj9J6d4=", + "_parent": { + "$ref": "AAAAAAFk73lGFD9Ae88=" + }, + "model": { + "$ref": "AAAAAAFk7Aze6dcrc1c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -120, + "top": -42, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1392, + "top": 232, + "width": 186, + "height": 73, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73lGFT9BYnA=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73lGFT9GB9k=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73lGFT9HbmY=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73lGFj9IINY=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73lGFj9J6d4=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk73lGFz9KOEU=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk7A02MdlCa2M=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73lGFz9Ltlo=", + "_parent": { + "$ref": "AAAAAAFk73lGFz9KOEU=" + }, + "model": { + "$ref": "AAAAAAFk7A02MdlCa2M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1324, + "top": 278, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73lGFz9KOEU=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73lGFz9MHco=", + "_parent": { + "$ref": "AAAAAAFk73lGFz9KOEU=" + }, + "model": { + "$ref": "AAAAAAFk7A02MdlCa2M=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1324, + "top": 293, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73lGFz9KOEU=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73lGFz9NgmI=", + "_parent": { + "$ref": "AAAAAAFk73lGFz9KOEU=" + }, + "model": { + "$ref": "AAAAAAFk7A02MdlCa2M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1325, + "top": 248, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73lGFz9KOEU=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73h74TjND7o=" + }, + "tail": { + "$ref": "AAAAAAFk73lGFD9Ae88=" + }, + "lineStyle": 0, + "points": "1392:269;1259:269", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73lGFz9Ltlo=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73lGFz9MHco=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73lGFz9NgmI=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk73lS7T/kJ+8=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk7BCTH+oZOBE=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73lS7T/lhL4=", + "_parent": { + "$ref": "AAAAAAFk73lS7T/kJ+8=" + }, + "model": { + "$ref": "AAAAAAFk7BCTH+oZOBE=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73lS7j/mCSA=", + "_parent": { + "$ref": "AAAAAAFk73lS7T/lhL4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -364, + "top": -106, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73lS7j/neiM=", + "_parent": { + "$ref": "AAAAAAFk73lS7T/lhL4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 151, + "width": 180, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageCacheSerializer", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73lS7j/o/s4=", + "_parent": { + "$ref": "AAAAAAFk73lS7T/lhL4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 166, + "width": 180, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73lS7j/p0Bs=", + "_parent": { + "$ref": "AAAAAAFk73lS7T/lhL4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -364, + "top": -106, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1392, + "top": 144, + "width": 190, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73lS7j/mCSA=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73lS7j/neiM=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73lS7j/o/s4=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73lS7j/p0Bs=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73lS7j/qnkY=", + "_parent": { + "$ref": "AAAAAAFk73lS7T/kJ+8=" + }, + "model": { + "$ref": "AAAAAAFk7BCTH+oZOBE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1392, + "top": 184, + "width": 190, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73lS7j/rnIw=", + "_parent": { + "$ref": "AAAAAAFk73lS7T/kJ+8=" + }, + "model": { + "$ref": "AAAAAAFk7BCTH+oZOBE=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73lTBkAnqq4=", + "_parent": { + "$ref": "AAAAAAFk73lS7j/rnIw=" + }, + "model": { + "$ref": "AAAAAAFk7BE9ae7ahlI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1397, + "top": 199, + "width": 180, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(block)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1392, + "top": 194, + "width": 190, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73lS7z/sUS0=", + "_parent": { + "$ref": "AAAAAAFk73lS7T/kJ+8=" + }, + "model": { + "$ref": "AAAAAAFk7BCTH+oZOBE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -182, + "top": -53, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73lS7z/taLM=", + "_parent": { + "$ref": "AAAAAAFk73lS7T/kJ+8=" + }, + "model": { + "$ref": "AAAAAAFk7BCTH+oZOBE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -182, + "top": -53, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 1392, + "top": 144, + "width": 190, + "height": 73, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73lS7T/lhL4=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73lS7j/qnkY=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73lS7j/rnIw=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73lS7z/sUS0=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73lS7z/taLM=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk73lS8D/uZ3U=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk7BDJZOsigsQ=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73lS8D/vw4Y=", + "_parent": { + "$ref": "AAAAAAFk73lS8D/uZ3U=" + }, + "model": { + "$ref": "AAAAAAFk7BDJZOsigsQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1344, + "top": 190, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73lS8D/uZ3U=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73lS8T/wXJ4=", + "_parent": { + "$ref": "AAAAAAFk73lS8D/uZ3U=" + }, + "model": { + "$ref": "AAAAAAFk7BDJZOsigsQ=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1344, + "top": 205, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73lS8D/uZ3U=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73lS8T/xIGI=", + "_parent": { + "$ref": "AAAAAAFk73lS8D/uZ3U=" + }, + "model": { + "$ref": "AAAAAAFk7BDJZOsigsQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1345, + "top": 160, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73lS8D/uZ3U=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73iEuTk/DXw=" + }, + "tail": { + "$ref": "AAAAAAFk73lS7T/kJ+8=" + }, + "lineStyle": 0, + "points": "1392:181;1298:181", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73lS8D/vw4Y=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73lS8T/wXJ4=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73lS8T/xIGI=" + } + }, + { + "_type": "UMLEnumerationView", + "_id": "AAAAAAFk73oXOEnXF6M=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73oXOEnYM/M=", + "_parent": { + "$ref": "AAAAAAFk73oXOEnXF6M=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73oXOUnZGqo=", + "_parent": { + "$ref": "AAAAAAFk73oXOEnYM/M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 141, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«enumeration»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73oXOUnaTuY=", + "_parent": { + "$ref": "AAAAAAFk73oXOEnYM/M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 156, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageOptions", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73oXOUnbtpU=", + "_parent": { + "$ref": "AAAAAAFk73oXOEnYM/M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 171, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73oXOUncl3Q=", + "_parent": { + "$ref": "AAAAAAFk73oXOEnYM/M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -344, + "top": -184, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 136, + "width": 168, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73oXOUnZGqo=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73oXOUnaTuY=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73oXOUnbtpU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73oXOUncl3Q=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73oXOUndwdw=", + "_parent": { + "$ref": "AAAAAAFk73oXOEnXF6M=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -172, + "top": -92, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73oXOUneopY=", + "_parent": { + "$ref": "AAAAAAFk73oXOEnXF6M=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -172, + "top": -92, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73oXOknfauM=", + "_parent": { + "$ref": "AAAAAAFk73oXOEnXF6M=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -172, + "top": -92, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73oXOkngolg=", + "_parent": { + "$ref": "AAAAAAFk73oXOEnXF6M=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -172, + "top": -92, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLEnumerationLiteralCompartmentView", + "_id": "AAAAAAFk73oXOknhCSU=", + "_parent": { + "$ref": "AAAAAAFk73oXOEnXF6M=" + }, + "model": { + "$ref": "AAAAAAFUkhyNUo23oFw=" + }, + "subViews": [ + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73oXV0oe0Qc=", + "_parent": { + "$ref": "AAAAAAFk73oXOknhCSU=" + }, + "model": { + "$ref": "AAAAAAFUkhys4o27Ge0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 194, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "retryFailed", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73oXWEoh9sg=", + "_parent": { + "$ref": "AAAAAAFk73oXOknhCSU=" + }, + "model": { + "$ref": "AAAAAAFUkhza8o2/z9E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 209, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "lowPriority", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73oXWEokLBo=", + "_parent": { + "$ref": "AAAAAAFk73oXOknhCSU=" + }, + "model": { + "$ref": "AAAAAAFUkhzs8o3Fkdk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 224, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "progressiveLoad", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73oXWUonaWY=", + "_parent": { + "$ref": "AAAAAAFk73oXOknhCSU=" + }, + "model": { + "$ref": "AAAAAAFUkhz04o3ItAc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 239, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "refreshCached", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73oXWUoqVvU=", + "_parent": { + "$ref": "AAAAAAFk73oXOknhCSU=" + }, + "model": { + "$ref": "AAAAAAFUkhz84Y3L96A=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 254, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "continueInBackground", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73oXWkote3Q=", + "_parent": { + "$ref": "AAAAAAFk73oXOknhCSU=" + }, + "model": { + "$ref": "AAAAAAFUkh0C6Y3O214=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 269, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "handleCookies", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73oXWkowQKc=", + "_parent": { + "$ref": "AAAAAAFk73oXOknhCSU=" + }, + "model": { + "$ref": "AAAAAAFUkh2TUY3YpnQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 284, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "allowInvalidSSLCertificates", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73oXW0oz8VE=", + "_parent": { + "$ref": "AAAAAAFk73oXOknhCSU=" + }, + "model": { + "$ref": "AAAAAAFUkh2bqY3bxlE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 299, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "highPriority", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73oXW0o2yV0=", + "_parent": { + "$ref": "AAAAAAFk73oXOknhCSU=" + }, + "model": { + "$ref": "AAAAAAFUkh2p4Y3e22E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 314, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "delayPlaceholder", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73oXXEo5owM=", + "_parent": { + "$ref": "AAAAAAFk73oXOknhCSU=" + }, + "model": { + "$ref": "AAAAAAFUkh2x+Y3hQmw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 329, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "transformAnimatedImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73oXXEo8/J4=", + "_parent": { + "$ref": "AAAAAAFk73oXOknhCSU=" + }, + "model": { + "$ref": "AAAAAAFUkh31iY3ox50=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 344, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "avoidAutoSetImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73oXXUo/jx0=", + "_parent": { + "$ref": "AAAAAAFk73oXOknhCSU=" + }, + "model": { + "$ref": "AAAAAAFkzPKuPGy7i4M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 359, + "width": 158, + "height": 13, + "autoResize": false, + "underline": false, + "text": "scaleDownLargeImages", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 189, + "width": 168, + "height": 188, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 136, + "width": 168, + "height": 241, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73oXOEnYM/M=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73oXOUndwdw=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73oXOUneopY=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73oXOknfauM=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73oXOkngolg=" + }, + "suppressLiterals": false, + "enumerationLiteralCompartment": { + "$ref": "AAAAAAFk73oXOknhCSU=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk73oXPEni50k=", + "_parent": { + "$ref": "AAAAAAFk726wIhJXSAY=" + }, + "model": { + "$ref": "AAAAAAFk6+vKjo5YRUw=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73oXPEnj5DU=", + "_parent": { + "$ref": "AAAAAAFk73oXPEni50k=" + }, + "model": { + "$ref": "AAAAAAFk6+vKjo5YRUw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 294, + "top": 225, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73oXPEni50k=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73oXPEnka5E=", + "_parent": { + "$ref": "AAAAAAFk73oXPEni50k=" + }, + "model": { + "$ref": "AAAAAAFk6+vKjo5YRUw=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 294, + "top": 240, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73oXPEni50k=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73oXPEnlOJI=", + "_parent": { + "$ref": "AAAAAAFk73oXPEni50k=" + }, + "model": { + "$ref": "AAAAAAFk6+vKjo5YRUw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 295, + "top": 195, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73oXPEni50k=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73oXOEnXF6M=" + }, + "tail": { + "$ref": "AAAAAAFk727jFxKPv/M=" + }, + "lineStyle": 0, + "points": "416:216;175:216", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73oXPEnj5DU=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73oXPEnka5E=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73oXPEnlOJI=" + } + } + ] + }, + { + "_type": "UMLClassDiagram", + "_id": "AAAAAAFk73uRhlJQp8M=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Coders Diagram", + "visible": true, + "defaultDiagram": false, + "ownedViews": [ + { + "_type": "UMLClassView", + "_id": "AAAAAAFk73vslFKgg7c=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73vslFKhzow=", + "_parent": { + "$ref": "AAAAAAFk73vslFKgg7c=" + }, + "model": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73vslFKiO8U=", + "_parent": { + "$ref": "AAAAAAFk73vslFKhzow=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -596, + "top": -258, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73vslFKjgjw=", + "_parent": { + "$ref": "AAAAAAFk73vslFKhzow=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 23, + "width": 194, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCodersManager", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73vslFKkDWY=", + "_parent": { + "$ref": "AAAAAAFk73vslFKhzow=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 38, + "width": 194, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73vslFKlgfY=", + "_parent": { + "$ref": "AAAAAAFk73vslFKhzow=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -596, + "top": -258, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 16, + "width": 204, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73vslFKiO8U=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73vslFKjgjw=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73vslFKkDWY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73vslFKlgfY=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73vslFKme/I=", + "_parent": { + "$ref": "AAAAAAFk73vslFKgg7c=" + }, + "model": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73vstVLGjcU=", + "_parent": { + "$ref": "AAAAAAFk73vslFKme/I=" + }, + "model": { + "$ref": "AAAAAAFfKvIMwCceZuI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 61, + "width": 194, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedInstance", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk73vstVLJQ50=", + "_parent": { + "$ref": "AAAAAAFk73vslFKme/I=" + }, + "model": { + "$ref": "AAAAAAFfKvJtjym0wQE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 76, + "width": 194, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+coders: Array ", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 56, + "width": 204, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73vslVKnOO4=", + "_parent": { + "$ref": "AAAAAAFk73vslFKgg7c=" + }, + "model": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73vstlLM4C8=", + "_parent": { + "$ref": "AAAAAAFk73vslVKnOO4=" + }, + "model": { + "$ref": "AAAAAAFfKvJK9yjW40I=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 99, + "width": 194, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+add(coder)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73vst1LPKXY=", + "_parent": { + "$ref": "AAAAAAFk73vslVKnOO4=" + }, + "model": { + "$ref": "AAAAAAFfKvPFeTMmARs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 114, + "width": 194, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+remove(coder)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 94, + "width": 204, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73vslVKotr0=", + "_parent": { + "$ref": "AAAAAAFk73vslFKgg7c=" + }, + "model": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -298, + "top": -129, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73vslVKpuHw=", + "_parent": { + "$ref": "AAAAAAFk73vslFKgg7c=" + }, + "model": { + "$ref": "AAAAAAFfKukEJfyENXE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -298, + "top": -129, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 16, + "top": 16, + "width": 204, + "height": 116, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73vslFKhzow=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73vslFKme/I=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73vslVKnOO4=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73vslVKotr0=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73vslVKpuHw=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk73whtFLUsGQ=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73whtFLVta0=", + "_parent": { + "$ref": "AAAAAAFk73whtFLUsGQ=" + }, + "model": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73whtFLWArs=", + "_parent": { + "$ref": "AAAAAAFk73whtFLVta0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 21, + "width": 233, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73whtFLXGIM=", + "_parent": { + "$ref": "AAAAAAFk73whtFLVta0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 36, + "width": 233, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73whtFLYn2Y=", + "_parent": { + "$ref": "AAAAAAFk73whtFLVta0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 51, + "width": 233, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73whtFLZtns=", + "_parent": { + "$ref": "AAAAAAFk73whtFLVta0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -550, + "top": -82, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 312, + "top": 16, + "width": 243, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73whtFLWArs=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73whtFLXGIM=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73whtFLYn2Y=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73whtFLZtns=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73whtFLabgw=", + "_parent": { + "$ref": "AAAAAAFk73whtFLUsGQ=" + }, + "model": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -275, + "top": -41, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73whtFLbOW0=", + "_parent": { + "$ref": "AAAAAAFk73whtFLUsGQ=" + }, + "model": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73whvFMFCic=", + "_parent": { + "$ref": "AAAAAAFk73whtFLbOW0=" + }, + "model": { + "$ref": "AAAAAAFfKtg9W998WOc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 74, + "width": 257, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+canDecode(data): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73whvVMINnY=", + "_parent": { + "$ref": "AAAAAAFk73whtFLbOW0=" + }, + "model": { + "$ref": "AAAAAAFfKtrKNePvsF8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 89, + "width": 257, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+decodedImage(data, options): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73whvVMLIwE=", + "_parent": { + "$ref": "AAAAAAFk73whtFLbOW0=" + }, + "model": { + "$ref": "AAAAAAFfKuUPYO6usi8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 104, + "width": 257, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+canEncode(format): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73whvlMOz+E=", + "_parent": { + "$ref": "AAAAAAFk73whtFLbOW0=" + }, + "model": { + "$ref": "AAAAAAFfKuW6ofDJluc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 119, + "width": 257, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+encodedData(image, format, options): Data", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 312, + "top": 69, + "width": 267, + "height": 68, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73whtVLcG/w=", + "_parent": { + "$ref": "AAAAAAFk73whtFLUsGQ=" + }, + "model": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -275, + "top": -41, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73whtVLdjn8=", + "_parent": { + "$ref": "AAAAAAFk73whtFLUsGQ=" + }, + "model": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -275, + "top": -41, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 312, + "top": 16, + "width": 267, + "height": 132, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73whtFLVta0=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73whtFLabgw=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73whtFLbOW0=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73whtVLcG/w=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73whtVLdjn8=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk73whtlLePuw=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFfKu3J8hGXH0g=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73whtlLfcyc=", + "_parent": { + "$ref": "AAAAAAFk73whtlLePuw=" + }, + "model": { + "$ref": "AAAAAAFfKu3J8hGXH0g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 265, + "top": 85, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73whtlLePuw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73whtlLghFI=", + "_parent": { + "$ref": "AAAAAAFk73whtlLePuw=" + }, + "model": { + "$ref": "AAAAAAFfKu3J8hGXH0g=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 265, + "top": 70, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73whtlLePuw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73whtlLhAS0=", + "_parent": { + "$ref": "AAAAAAFk73whtlLePuw=" + }, + "model": { + "$ref": "AAAAAAFfKu3J8hGXH0g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 265, + "top": 115, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73whtlLePuw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73whtFLUsGQ=" + }, + "tail": { + "$ref": "AAAAAAFk73vslFKgg7c=" + }, + "lineStyle": 0, + "points": "219:106;312:106", + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73whtlLfcyc=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73whtlLghFI=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73whtlLhAS0=" + } + }, + { + "_type": "UMLEnumerationView", + "_id": "AAAAAAFk73yJnVMZDjk=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73yJnVMadso=", + "_parent": { + "$ref": "AAAAAAFk73yJnVMZDjk=" + }, + "model": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73yJnVMbDIE=", + "_parent": { + "$ref": "AAAAAAFk73yJnVMadso=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 597, + "top": 21, + "width": 159, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«enumeration»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73yJnVMcpQA=", + "_parent": { + "$ref": "AAAAAAFk73yJnVMadso=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 597, + "top": 36, + "width": 159, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCoderOptions", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73yJnVMdiHw=", + "_parent": { + "$ref": "AAAAAAFk73yJnVMadso=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 597, + "top": 51, + "width": 159, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73yJnlMeSP0=", + "_parent": { + "$ref": "AAAAAAFk73yJnVMadso=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -702, + "top": -112, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 592, + "top": 16, + "width": 169, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73yJnVMbDIE=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73yJnVMcpQA=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73yJnVMdiHw=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73yJnlMeSP0=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73yJnlMf+Os=", + "_parent": { + "$ref": "AAAAAAFk73yJnVMZDjk=" + }, + "model": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -351, + "top": -56, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73yJnlMgkmQ=", + "_parent": { + "$ref": "AAAAAAFk73yJnVMZDjk=" + }, + "model": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -351, + "top": -56, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73yJnlMheUs=", + "_parent": { + "$ref": "AAAAAAFk73yJnVMZDjk=" + }, + "model": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -351, + "top": -56, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73yJnlMi6zw=", + "_parent": { + "$ref": "AAAAAAFk73yJnVMZDjk=" + }, + "model": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -351, + "top": -56, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLEnumerationLiteralCompartmentView", + "_id": "AAAAAAFk73yJnlMj540=", + "_parent": { + "$ref": "AAAAAAFk73yJnVMZDjk=" + }, + "model": { + "$ref": "AAAAAAFkyzVnxm2Ab1g=" + }, + "subViews": [ + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73yJpFNDCv8=", + "_parent": { + "$ref": "AAAAAAFk73yJnlMj540=" + }, + "model": { + "$ref": "AAAAAAFkyzXADnBSFdc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 597, + "top": 74, + "width": 159, + "height": 13, + "autoResize": false, + "underline": false, + "text": "decodeFirstFrameOnly", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73yJpVNGuOk=", + "_parent": { + "$ref": "AAAAAAFk73yJnlMj540=" + }, + "model": { + "$ref": "AAAAAAFkyzZGYHJ5+5E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 597, + "top": 89, + "width": 159, + "height": 13, + "autoResize": false, + "underline": false, + "text": "decodeScaleFactor", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73yJplNJzkI=", + "_parent": { + "$ref": "AAAAAAFk73yJnlMj540=" + }, + "model": { + "$ref": "AAAAAAFkyzbTKndtAbI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 597, + "top": 104, + "width": 159, + "height": 13, + "autoResize": false, + "underline": false, + "text": "encodeFirstFrameOnly", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk73yJplNMxS4=", + "_parent": { + "$ref": "AAAAAAFk73yJnlMj540=" + }, + "model": { + "$ref": "AAAAAAFkyzbx8ni4xXQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 597, + "top": 119, + "width": 159, + "height": 13, + "autoResize": false, + "underline": false, + "text": "encodeCompressionQuality", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 592, + "top": 69, + "width": 169, + "height": 68, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 592, + "top": 16, + "width": 169, + "height": 121, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73yJnVMadso=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73yJnlMf+Os=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73yJnlMgkmQ=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73yJnlMheUs=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73yJnlMi6zw=" + }, + "suppressLiterals": false, + "enumerationLiteralCompartment": { + "$ref": "AAAAAAFk73yJnlMj540=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk73zJCFNRMfQ=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73zJCFNSnOo=", + "_parent": { + "$ref": "AAAAAAFk73zJCFNRMfQ=" + }, + "model": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73zJCFNTaJc=", + "_parent": { + "$ref": "AAAAAAFk73zJCFNSnOo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 197, + "width": 245, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73zJCFNUrfc=", + "_parent": { + "$ref": "AAAAAAFk73zJCFNSnOo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 212, + "width": 245, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDProgressiveImageCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73zJCFNViMA=", + "_parent": { + "$ref": "AAAAAAFk73zJCFNSnOo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 227, + "width": 245, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73zJCFNWQUE=", + "_parent": { + "$ref": "AAAAAAFk73zJCFNSnOo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -768, + "top": -172, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 192, + "width": 255, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73zJCFNTaJc=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73zJCFNUrfc=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73zJCFNViMA=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73zJCFNWQUE=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73zJCFNX5sI=", + "_parent": { + "$ref": "AAAAAAFk73zJCFNRMfQ=" + }, + "model": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -384, + "top": -86, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73zJCFNYT7M=", + "_parent": { + "$ref": "AAAAAAFk73zJCFNRMfQ=" + }, + "model": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73zJDlN36as=", + "_parent": { + "$ref": "AAAAAAFk73zJCFNYT7M=" + }, + "model": { + "$ref": "AAAAAAFfKudnG/biyzM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 250, + "width": 269, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+canIncrementalDecode(data): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73zJD1N6CIQ=", + "_parent": { + "$ref": "AAAAAAFk73zJCFNYT7M=" + }, + "model": { + "$ref": "AAAAAAFky0Ig1o8YU4s=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 265, + "width": 269, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(options)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73zJD1N9dXw=", + "_parent": { + "$ref": "AAAAAAFk73zJCFNYT7M=" + }, + "model": { + "$ref": "AAAAAAFky0LqApDu034=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 280, + "width": 269, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+updateIncrementalData(data, finished)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73zJEFOA/6g=", + "_parent": { + "$ref": "AAAAAAFk73zJCFNYT7M=" + }, + "model": { + "$ref": "AAAAAAFfKugU/PmNPJQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 295, + "width": 269, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+incrementalDecodedImage(options): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 245, + "width": 279, + "height": 68, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73zJCFNZGCo=", + "_parent": { + "$ref": "AAAAAAFk73zJCFNRMfQ=" + }, + "model": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -384, + "top": -86, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73zJCVNa5CM=", + "_parent": { + "$ref": "AAAAAAFk73zJCFNRMfQ=" + }, + "model": { + "$ref": "AAAAAAFfKuaHevMvVkQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -384, + "top": -86, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 16, + "top": 192, + "width": 279, + "height": 132, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73zJCFNSnOo=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73zJCFNX5sI=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73zJCFNYT7M=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73zJCFNZGCo=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73zJCVNa5CM=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk73zjJlOEXDY=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk73zjJlOF73M=", + "_parent": { + "$ref": "AAAAAAFk73zjJlOEXDY=" + }, + "model": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk73zjJlOGuUg=", + "_parent": { + "$ref": "AAAAAAFk73zjJlOF73M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 325, + "top": 197, + "width": 162, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73zjJ1OHbws=", + "_parent": { + "$ref": "AAAAAAFk73zjJlOF73M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 325, + "top": 212, + "width": 162, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDAnimatedImageCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73zjJ1OIU9Q=", + "_parent": { + "$ref": "AAAAAAFk73zjJlOF73M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 325, + "top": 227, + "width": 162, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk73zjJ1OJrko=", + "_parent": { + "$ref": "AAAAAAFk73zjJlOF73M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -780, + "top": -206, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 320, + "top": 192, + "width": 172, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk73zjJlOGuUg=" + }, + "nameLabel": { + "$ref": "AAAAAAFk73zjJ1OHbws=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk73zjJ1OIU9Q=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73zjJ1OJrko=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk73zjJ1OKp2k=", + "_parent": { + "$ref": "AAAAAAFk73zjJlOEXDY=" + }, + "model": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -390, + "top": -103, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk73zjJ1OLvmE=", + "_parent": { + "$ref": "AAAAAAFk73zjJlOEXDY=" + }, + "model": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk73zjLFOqJXA=", + "_parent": { + "$ref": "AAAAAAFk73zjJ1OLvmE=" + }, + "model": { + "$ref": "AAAAAAFky0rWqbVSTp8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 325, + "top": 250, + "width": 186, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(data, options)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 320, + "top": 245, + "width": 196, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk73zjJ1OMOG4=", + "_parent": { + "$ref": "AAAAAAFk73zjJlOEXDY=" + }, + "model": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -390, + "top": -103, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk73zjJ1ONGMM=", + "_parent": { + "$ref": "AAAAAAFk73zjJlOEXDY=" + }, + "model": { + "$ref": "AAAAAAFky0kNeqcckGY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -390, + "top": -103, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 320, + "top": 192, + "width": 196, + "height": 87, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk73zjJlOF73M=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk73zjJ1OKp2k=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk73zjJ1OLvmE=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk73zjJ1OMOG4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk73zjJ1ONGMM=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk730En1Our4E=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk730En1OvWUc=", + "_parent": { + "$ref": "AAAAAAFk730En1Our4E=" + }, + "model": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk730En1OwtdY=", + "_parent": { + "$ref": "AAAAAAFk730En1OvWUc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 565, + "top": 197, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk730En1OxWPo=", + "_parent": { + "$ref": "AAAAAAFk730En1OvWUc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 565, + "top": 212, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDAnimatedImageProvider", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk730En1OyP20=", + "_parent": { + "$ref": "AAAAAAFk730En1OvWUc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 565, + "top": 227, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk730En1OzXBw=", + "_parent": { + "$ref": "AAAAAAFk730En1OvWUc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -874, + "top": -236, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 560, + "top": 192, + "width": 216, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk730En1OwtdY=" + }, + "nameLabel": { + "$ref": "AAAAAAFk730En1OxWPo=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk730En1OyP20=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk730En1OzXBw=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk730En1O0vEs=", + "_parent": { + "$ref": "AAAAAAFk730En1Our4E=" + }, + "model": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -437, + "top": -118, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk730En1O1Pxk=", + "_parent": { + "$ref": "AAAAAAFk730En1Our4E=" + }, + "model": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk730EpVPUbWU=", + "_parent": { + "$ref": "AAAAAAFk730En1O1Pxk=" + }, + "model": { + "$ref": "AAAAAAFky0WaTJkCiCI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 565, + "top": 250, + "width": 230, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animatedImageData(): Data", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk730EplPXTec=", + "_parent": { + "$ref": "AAAAAAFk730En1O1Pxk=" + }, + "model": { + "$ref": "AAAAAAFky0bXOZxXYmQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 565, + "top": 265, + "width": 230, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animatedImageFrameCount(): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk730EplPa4p0=", + "_parent": { + "$ref": "AAAAAAFk730En1O1Pxk=" + }, + "model": { + "$ref": "AAAAAAFky0d4BJ5ka1A=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 565, + "top": 280, + "width": 230, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animatedImageLoopCount(): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk730Ep1Pd/rI=", + "_parent": { + "$ref": "AAAAAAFk730En1O1Pxk=" + }, + "model": { + "$ref": "AAAAAAFky0fVlaBxwo0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 565, + "top": 295, + "width": 230, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animatedImageFrame(index): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk730Ep1PgUYc=", + "_parent": { + "$ref": "AAAAAAFk730En1O1Pxk=" + }, + "model": { + "$ref": "AAAAAAFky0hX/6NafH4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 565, + "top": 310, + "width": 230, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+animatedImageDuration(index): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 560, + "top": 245, + "width": 240, + "height": 83, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk730En1O2C/k=", + "_parent": { + "$ref": "AAAAAAFk730En1Our4E=" + }, + "model": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -437, + "top": -118, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk730En1O3qfE=", + "_parent": { + "$ref": "AAAAAAFk730En1Our4E=" + }, + "model": { + "$ref": "AAAAAAFky0S/MZVxPY0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -437, + "top": -118, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 560, + "top": 192, + "width": 240, + "height": 147, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk730En1OvWUc=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk730En1O0vEs=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk730En1O1Pxk=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk730En1O2C/k=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk730En1O3qfE=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk731JFlPkYmQ=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFfKul3rf0/okM=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk731JFlPlK/M=", + "_parent": { + "$ref": "AAAAAAFk731JFlPkYmQ=" + }, + "model": { + "$ref": "AAAAAAFfKul3rf0/okM=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk731JFlPmJ4I=", + "_parent": { + "$ref": "AAAAAAFk731JFlPlK/M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -614, + "top": 26, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk731JFlPnEoM=", + "_parent": { + "$ref": "AAAAAAFk731JFlPlK/M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 439, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageIOCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk731JFlPoY6c=", + "_parent": { + "$ref": "AAAAAAFk731JFlPlK/M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 454, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk731JFlPpGHA=", + "_parent": { + "$ref": "AAAAAAFk731JFlPlK/M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -614, + "top": 26, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 432, + "width": 128, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk731JFlPmJ4I=" + }, + "nameLabel": { + "$ref": "AAAAAAFk731JFlPnEoM=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk731JFlPoY6c=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk731JFlPpGHA=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk731JFlPqbjk=", + "_parent": { + "$ref": "AAAAAAFk731JFlPkYmQ=" + }, + "model": { + "$ref": "AAAAAAFfKul3rf0/okM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 472, + "width": 128, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk731JF1PrmWk=", + "_parent": { + "$ref": "AAAAAAFk731JFlPkYmQ=" + }, + "model": { + "$ref": "AAAAAAFfKul3rf0/okM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 482, + "width": 128, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk731JF1PsXoQ=", + "_parent": { + "$ref": "AAAAAAFk731JFlPkYmQ=" + }, + "model": { + "$ref": "AAAAAAFfKul3rf0/okM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -307, + "top": 13, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk731JF1Ptlso=", + "_parent": { + "$ref": "AAAAAAFk731JFlPkYmQ=" + }, + "model": { + "$ref": "AAAAAAFfKul3rf0/okM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -307, + "top": 13, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 16, + "top": 432, + "width": 128, + "height": 60, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk731JFlPlK/M=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk731JFlPqbjk=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk731JF1PrmWk=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk731JF1PsXoQ=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk731JF1Ptlso=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk731JF1PuQuQ=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFfKu+znBqqvWQ=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk731JF1Pvvm8=", + "_parent": { + "$ref": "AAAAAAFk731JF1PuQuQ=" + }, + "model": { + "$ref": "AAAAAAFfKu+znBqqvWQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 49, + "top": 370, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk731JF1PuQuQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk731JF1PwA7U=", + "_parent": { + "$ref": "AAAAAAFk731JF1PuQuQ=" + }, + "model": { + "$ref": "AAAAAAFfKu+znBqqvWQ=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 34, + "top": 370, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk731JF1PuQuQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk731JF1Pxz64=", + "_parent": { + "$ref": "AAAAAAFk731JF1PuQuQ=" + }, + "model": { + "$ref": "AAAAAAFfKu+znBqqvWQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 78, + "top": 371, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk731JF1PuQuQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73zJCFNRMfQ=" + }, + "tail": { + "$ref": "AAAAAAFk731JFlPkYmQ=" + }, + "lineStyle": 0, + "points": "64:432;64:323", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk731JF1Pvvm8=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk731JF1PwA7U=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk731JF1Pxz64=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk731pUFQZAVQ=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk731pUFQa6C4=", + "_parent": { + "$ref": "AAAAAAFk731pUFQZAVQ=" + }, + "model": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk731pUFQbu8w=", + "_parent": { + "$ref": "AAAAAAFk731pUFQa6C4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -764, + "top": -22, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk731pUFQc/Qg=", + "_parent": { + "$ref": "AAAAAAFk731pUFQa6C4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 157, + "top": 439, + "width": 129, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageWebPCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk731pUFQdTGQ=", + "_parent": { + "$ref": "AAAAAAFk731pUFQa6C4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 157, + "top": 454, + "width": 129, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk731pUFQe9HE=", + "_parent": { + "$ref": "AAAAAAFk731pUFQa6C4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -764, + "top": -22, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 152, + "top": 432, + "width": 139, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk731pUFQbu8w=" + }, + "nameLabel": { + "$ref": "AAAAAAFk731pUFQc/Qg=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk731pUFQdTGQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk731pUFQe9HE=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk731pUFQfCx0=", + "_parent": { + "$ref": "AAAAAAFk731pUFQZAVQ=" + }, + "model": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 152, + "top": 472, + "width": 139, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk731pUVQghSU=", + "_parent": { + "$ref": "AAAAAAFk731pUFQZAVQ=" + }, + "model": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 152, + "top": 482, + "width": 139, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk731pUVQhuR4=", + "_parent": { + "$ref": "AAAAAAFk731pUFQZAVQ=" + }, + "model": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -382, + "top": -11, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk731pUVQim30=", + "_parent": { + "$ref": "AAAAAAFk731pUFQZAVQ=" + }, + "model": { + "$ref": "AAAAAAFfKunO1f612hU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -382, + "top": -11, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 152, + "top": 432, + "width": 139, + "height": 60, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk731pUFQa6C4=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk731pUFQfCx0=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk731pUVQghSU=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk731pUVQhuR4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk731pUVQim30=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk732EOFRANvI=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk732EOFRBFMk=", + "_parent": { + "$ref": "AAAAAAFk732EOFRANvI=" + }, + "model": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk732EOFRCrns=", + "_parent": { + "$ref": "AAAAAAFk732EOFRBFMk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -970, + "top": -38, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk732EOFRDP2Y=", + "_parent": { + "$ref": "AAAAAAFk732EOFRBFMk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": 439, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageGIFCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk732EOFREgEw=", + "_parent": { + "$ref": "AAAAAAFk732EOFRBFMk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 309, + "top": 454, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk732EOFRFwnk=", + "_parent": { + "$ref": "AAAAAAFk732EOFRBFMk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -970, + "top": -38, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 432, + "width": 128, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk732EOFRCrns=" + }, + "nameLabel": { + "$ref": "AAAAAAFk732EOFRDP2Y=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk732EOFREgEw=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk732EOFRFwnk=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk732EOFRGYp4=", + "_parent": { + "$ref": "AAAAAAFk732EOFRANvI=" + }, + "model": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 472, + "width": 128, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk732EOVRHZhc=", + "_parent": { + "$ref": "AAAAAAFk732EOFRANvI=" + }, + "model": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 304, + "top": 482, + "width": 128, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk732EOVRIKzY=", + "_parent": { + "$ref": "AAAAAAFk732EOFRANvI=" + }, + "model": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -485, + "top": -19, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk732EOVRJde0=", + "_parent": { + "$ref": "AAAAAAFk732EOFRANvI=" + }, + "model": { + "$ref": "AAAAAAFfKumijf36cE8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -485, + "top": -19, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 304, + "top": 432, + "width": 128, + "height": 60, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk732EOFRBFMk=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk732EOFRGYp4=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk732EOVRHZhc=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk732EOVRIKzY=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk732EOVRJde0=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk732EOVRKddk=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFfKu8vtRgLlUU=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk732EOVRL9xo=", + "_parent": { + "$ref": "AAAAAAFk732EOVRKddk=" + }, + "model": { + "$ref": "AAAAAAFfKu8vtRgLlUU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 307, + "top": 361, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk732EOVRKddk=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk732EOVRM97U=", + "_parent": { + "$ref": "AAAAAAFk732EOVRKddk=" + }, + "model": { + "$ref": "AAAAAAFfKu8vtRgLlUU=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 307, + "top": 376, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk732EOVRKddk=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk732EOVRNU3o=", + "_parent": { + "$ref": "AAAAAAFk732EOVRKddk=" + }, + "model": { + "$ref": "AAAAAAFfKu8vtRgLlUU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 308, + "top": 331, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk732EOVRKddk=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73zJCFNRMfQ=" + }, + "tail": { + "$ref": "AAAAAAFk732EOFRANvI=" + }, + "lineStyle": 0, + "points": "360:432;360:352;256:352;256:323", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk732EOVRL9xo=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk732EOVRM97U=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk732EOVRNU3o=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk732ViVR1WXM=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk732ViVR228w=", + "_parent": { + "$ref": "AAAAAAFk732ViVR1WXM=" + }, + "model": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk732ViVR39Tw=", + "_parent": { + "$ref": "AAAAAAFk732ViVR228w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1134, + "top": -26, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk732ViVR4zQQ=", + "_parent": { + "$ref": "AAAAAAFk732ViVR228w=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 445, + "top": 439, + "width": 130, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageAPNGCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk732ViVR5DuQ=", + "_parent": { + "$ref": "AAAAAAFk732ViVR228w=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 445, + "top": 454, + "width": 130, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk732ViVR6GY4=", + "_parent": { + "$ref": "AAAAAAFk732ViVR228w=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1134, + "top": -26, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 440, + "top": 432, + "width": 140, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk732ViVR39Tw=" + }, + "nameLabel": { + "$ref": "AAAAAAFk732ViVR4zQQ=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk732ViVR5DuQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk732ViVR6GY4=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk732ViVR7FPU=", + "_parent": { + "$ref": "AAAAAAFk732ViVR1WXM=" + }, + "model": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 440, + "top": 472, + "width": 140, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk732ViVR86vU=", + "_parent": { + "$ref": "AAAAAAFk732ViVR1WXM=" + }, + "model": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 440, + "top": 482, + "width": 140, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk732ViVR9/6w=", + "_parent": { + "$ref": "AAAAAAFk732ViVR1WXM=" + }, + "model": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -567, + "top": -13, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk732ViVR+1a4=", + "_parent": { + "$ref": "AAAAAAFk732ViVR1WXM=" + }, + "model": { + "$ref": "AAAAAAFky08wi8R0DcY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -567, + "top": -13, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 440, + "top": 432, + "width": 140, + "height": 60, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk732ViVR228w=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk732ViVR7FPU=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk732ViVR86vU=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk732ViVR9/6w=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk732ViVR+1a4=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk732VilR/gDc=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk732VilSAEWs=", + "_parent": { + "$ref": "AAAAAAFk732VilR/gDc=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 481, + "top": 348, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk732VilR/gDc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk732VilSBaks=", + "_parent": { + "$ref": "AAAAAAFk732VilR/gDc=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 466, + "top": 348, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk732VilR/gDc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk732VilSCGEY=", + "_parent": { + "$ref": "AAAAAAFk732VilR/gDc=" + }, + "model": { + "$ref": "AAAAAAFfKu/8NRxLVBY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 510, + "top": 349, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk732VilR/gDc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73zjJlOEXDY=" + }, + "tail": { + "$ref": "AAAAAAFk732ViVR1WXM=" + }, + "lineStyle": 0, + "points": "496:432;496:278", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk732VilSAEWs=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk732VilSBaks=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk732VilSCGEY=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAFk738aHFS688U=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk738aHFS48u4=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk738aHVS7Dn0=", + "_parent": { + "$ref": "AAAAAAFk738aHFS688U=" + }, + "model": { + "$ref": "AAAAAAFk738aHFS48u4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 537, + "top": 232, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk738aHFS688U=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk738aHVS8bFU=", + "_parent": { + "$ref": "AAAAAAFk738aHFS688U=" + }, + "model": { + "$ref": "AAAAAAFk738aHFS48u4=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 537, + "top": 217, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk738aHFS688U=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk738aHVS9oz8=", + "_parent": { + "$ref": "AAAAAAFk738aHFS688U=" + }, + "model": { + "$ref": "AAAAAAFk738aHFS48u4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 537, + "top": 262, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk738aHFS688U=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk730En1Our4E=" + }, + "tail": { + "$ref": "AAAAAAFk73zjJlOEXDY=" + }, + "lineStyle": 0, + "points": "515:253;560:253", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk738aHVS7Dn0=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk738aHVS8bFU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk738aHVS9oz8=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAFk73/AjlUBKiw=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk73/AjVT/3Vw=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73/AjlUCStI=", + "_parent": { + "$ref": "AAAAAAFk73/AjlUBKiw=" + }, + "model": { + "$ref": "AAAAAAFk73/AjVT/3Vw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 200, + "top": 115, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73/AjlUBKiw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73/AjlUDo1Q=", + "_parent": { + "$ref": "AAAAAAFk73/AjlUBKiw=" + }, + "model": { + "$ref": "AAAAAAFk73/AjVT/3Vw=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 200, + "top": 100, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73/AjlUBKiw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73/AjlUEQ7A=", + "_parent": { + "$ref": "AAAAAAFk73/AjlUBKiw=" + }, + "model": { + "$ref": "AAAAAAFk73/AjVT/3Vw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 200, + "top": 145, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73/AjlUBKiw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73whtFLUsGQ=" + }, + "tail": { + "$ref": "AAAAAAFk73zJCFNRMfQ=" + }, + "lineStyle": 0, + "points": "200:192;200:136;312:136", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73/AjlUCStI=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73/AjlUDo1Q=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73/AjlUEQ7A=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAFk73/PX1USYHQ=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk73/PXlUQYl8=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73/PX1UT6E0=", + "_parent": { + "$ref": "AAAAAAFk73/PX1USYHQ=" + }, + "model": { + "$ref": "AAAAAAFk73/PXlUQYl8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 418, + "top": 162, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73/PX1USYHQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73/PX1UUexE=", + "_parent": { + "$ref": "AAAAAAFk73/PX1USYHQ=" + }, + "model": { + "$ref": "AAAAAAFk73/PXlUQYl8=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 403, + "top": 162, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk73/PX1USYHQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk73/PX1UVmTY=", + "_parent": { + "$ref": "AAAAAAFk73/PX1USYHQ=" + }, + "model": { + "$ref": "AAAAAAFk73/PXlUQYl8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 447, + "top": 163, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk73/PX1USYHQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73whtFLUsGQ=" + }, + "tail": { + "$ref": "AAAAAAFk73zjJlOEXDY=" + }, + "lineStyle": 0, + "points": "433:192;433:147", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk73/PX1UT6E0=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk73/PX1UUexE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk73/PX1UVmTY=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk74Du0lUztOg=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk74Du0lUy4R4=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74Du0lU0Iqw=", + "_parent": { + "$ref": "AAAAAAFk74Du0lUztOg=" + }, + "model": { + "$ref": "AAAAAAFk74Du0lUy4R4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 162, + "top": 370, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74Du0lUztOg=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74Du0lU1CZ0=", + "_parent": { + "$ref": "AAAAAAFk74Du0lUztOg=" + }, + "model": { + "$ref": "AAAAAAFk74Du0lUy4R4=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 147, + "top": 370, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74Du0lUztOg=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74Du0lU2OSg=", + "_parent": { + "$ref": "AAAAAAFk74Du0lUztOg=" + }, + "model": { + "$ref": "AAAAAAFk74Du0lUy4R4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 191, + "top": 371, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74Du0lUztOg=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73zJCFNRMfQ=" + }, + "tail": { + "$ref": "AAAAAAFk731pUFQZAVQ=" + }, + "lineStyle": 0, + "points": "177:432;177:323", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74Du0lU0Iqw=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74Du0lU1CZ0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74Du0lU2OSg=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk74ElK1VFijM=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk74ElK1VEr6I=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74ElLFVGs0s=", + "_parent": { + "$ref": "AAAAAAFk74ElK1VFijM=" + }, + "model": { + "$ref": "AAAAAAFk74ElK1VEr6I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 297, + "top": 379, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74ElK1VFijM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74ElLFVH4vM=", + "_parent": { + "$ref": "AAAAAAFk74ElK1VFijM=" + }, + "model": { + "$ref": "AAAAAAFk74ElK1VEr6I=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 297, + "top": 364, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74ElK1VFijM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74ElLFVIlRA=", + "_parent": { + "$ref": "AAAAAAFk74ElK1VFijM=" + }, + "model": { + "$ref": "AAAAAAFk74ElK1VEr6I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 297, + "top": 409, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74ElK1VFijM=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73zjJlOEXDY=" + }, + "tail": { + "$ref": "AAAAAAFk731pUFQZAVQ=" + }, + "lineStyle": 0, + "points": "216:432;216:400;379:400;379:278", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74ElLFVGs0s=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74ElLFVH4vM=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74ElLFVIlRA=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk74ISXli/MPY=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk74ISXli+i9k=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74ISXljA7jQ=", + "_parent": { + "$ref": "AAAAAAFk74ISXli/MPY=" + }, + "model": { + "$ref": "AAAAAAFk74ISXli+i9k=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 392, + "top": 348, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74ISXli/MPY=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74ISXljBu1o=", + "_parent": { + "$ref": "AAAAAAFk74ISXli/MPY=" + }, + "model": { + "$ref": "AAAAAAFk74ISXli+i9k=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 377, + "top": 348, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74ISXli/MPY=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74ISXljCNYQ=", + "_parent": { + "$ref": "AAAAAAFk74ISXli/MPY=" + }, + "model": { + "$ref": "AAAAAAFk74ISXli+i9k=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 421, + "top": 349, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74ISXli/MPY=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73zjJlOEXDY=" + }, + "tail": { + "$ref": "AAAAAAFk732EOFRANvI=" + }, + "lineStyle": 0, + "points": "407:432;407:278", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74ISXljA7jQ=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74ISXljBu1o=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74ISXljCNYQ=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk74JHz1jR7ac=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk74JHz1jQLXI=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74JHz1jSafI=", + "_parent": { + "$ref": "AAAAAAFk74JHz1jR7ac=" + }, + "model": { + "$ref": "AAAAAAFk74JHz1jQLXI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 463, + "top": 321, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74JHz1jR7ac=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74JHz1jThPU=", + "_parent": { + "$ref": "AAAAAAFk74JHz1jR7ac=" + }, + "model": { + "$ref": "AAAAAAFk74JHz1jQLXI=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 463, + "top": 336, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74JHz1jR7ac=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74JHz1jUcV8=", + "_parent": { + "$ref": "AAAAAAFk74JHz1jR7ac=" + }, + "model": { + "$ref": "AAAAAAFk74JHz1jQLXI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 464, + "top": 291, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74JHz1jR7ac=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73zJCFNRMfQ=" + }, + "tail": { + "$ref": "AAAAAAFk732ViVR1WXM=" + }, + "lineStyle": 0, + "points": "464:432;464:312;294:312", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74JHz1jSafI=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74JHz1jThPU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74JHz1jUcV8=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk74PZ2VyYHEI=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74PZ2lyZH60=", + "_parent": { + "$ref": "AAAAAAFk74PZ2VyYHEI=" + }, + "model": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74PZ2lyaA24=", + "_parent": { + "$ref": "AAAAAAFk74PZ2lyZH60=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 188, + "top": -752, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74PZ2lyb14M=", + "_parent": { + "$ref": "AAAAAAFk74PZ2lyZH60=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 813, + "top": 47, + "width": 373, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCoderHelper", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74PZ2lyc/pc=", + "_parent": { + "$ref": "AAAAAAFk74PZ2lyZH60=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 813, + "top": 62, + "width": 373, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74PZ2lydlE0=", + "_parent": { + "$ref": "AAAAAAFk74PZ2lyZH60=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 188, + "top": -752, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 808, + "top": 40, + "width": 383, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74PZ2lyaA24=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74PZ2lyb14M=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74PZ2lyc/pc=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74PZ2lydlE0=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74PZ2lye0yk=", + "_parent": { + "$ref": "AAAAAAFk74PZ2VyYHEI=" + }, + "model": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 808, + "top": 80, + "width": 383, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74PZ21yfiuI=", + "_parent": { + "$ref": "AAAAAAFk74PZ2VyYHEI=" + }, + "model": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74PZ6FzJAMU=", + "_parent": { + "$ref": "AAAAAAFk74PZ21yfiuI=" + }, + "model": { + "$ref": "AAAAAAFky1HlrdRLhc8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 813, + "top": 95, + "width": 373, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+animatedImage(frames): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74PZ6FzMOZg=", + "_parent": { + "$ref": "AAAAAAFk74PZ21yfiuI=" + }, + "model": { + "$ref": "AAAAAAFky1MmItpS0IE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 813, + "top": 110, + "width": 373, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+frames(animatedImage): Array ", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74PZ6VzPSVU=", + "_parent": { + "$ref": "AAAAAAFk74PZ21yfiuI=" + }, + "model": { + "$ref": "AAAAAAFky1Qmzd9zXiU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 813, + "top": 125, + "width": 373, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+colorSpaceGetDeviceRGB(): CGColorSpace", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74PZ6VzSMfE=", + "_parent": { + "$ref": "AAAAAAFk74PZ21yfiuI=" + }, + "model": { + "$ref": "AAAAAAFky1S1OuHtMmU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 813, + "top": 140, + "width": 373, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+cgImageContainsAlpha(cgImage): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74PZ6lzVOT0=", + "_parent": { + "$ref": "AAAAAAFk74PZ21yfiuI=" + }, + "model": { + "$ref": "AAAAAAFky1WnxOVDz7I=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 813, + "top": 155, + "width": 373, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+cgImageCreateDecoded(cgImage): CGImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74PZ6lzYopY=", + "_parent": { + "$ref": "AAAAAAFk74PZ21yfiuI=" + }, + "model": { + "$ref": "AAAAAAFky1Zx3+iZ+Sc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 813, + "top": 170, + "width": 373, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+cgImageCreateDecoded(cgImage, orientation): CGImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74PZ61zb2Ms=", + "_parent": { + "$ref": "AAAAAAFk74PZ21yfiuI=" + }, + "model": { + "$ref": "AAAAAAFky1comezL+vc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 813, + "top": 185, + "width": 373, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+decodedImage(image): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74PZ61zexnw=", + "_parent": { + "$ref": "AAAAAAFk74PZ21yfiuI=" + }, + "model": { + "$ref": "AAAAAAFky1ei5PAhNRU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 813, + "top": 200, + "width": 373, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+decodedAndScaledDownImage(image, limitBytes): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74PZ61zhbuw=", + "_parent": { + "$ref": "AAAAAAFk74PZ21yfiuI=" + }, + "model": { + "$ref": "AAAAAAFky1gyjvRTopk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 813, + "top": 215, + "width": 373, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+imageOrientation(exifOrientation): UIImageOrientation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74PZ7FzkLZs=", + "_parent": { + "$ref": "AAAAAAFk74PZ21yfiuI=" + }, + "model": { + "$ref": "AAAAAAFky1jM4Pep+/8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 813, + "top": 230, + "width": 373, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+exifOrientation(imageOrientation): CGImagePropertyOrientation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 808, + "top": 90, + "width": 383, + "height": 158, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74PZ21ygiII=", + "_parent": { + "$ref": "AAAAAAFk74PZ2VyYHEI=" + }, + "model": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 94, + "top": -376, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74PZ21yh7fs=", + "_parent": { + "$ref": "AAAAAAFk74PZ2VyYHEI=" + }, + "model": { + "$ref": "AAAAAAFky1HOFNP2U1I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 94, + "top": -376, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 808, + "top": 40, + "width": 383, + "height": 208, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74PZ2lyZH60=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74PZ2lye0yk=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74PZ21yfiuI=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74PZ21ygiII=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74PZ21yh7fs=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk74PZ3Vyi7yo=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFfKuxM+AnptLY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74PZ3Vyjh0Q=", + "_parent": { + "$ref": "AAAAAAFk74PZ3Vyi7yo=" + }, + "model": { + "$ref": "AAAAAAFfKuxM+AnptLY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 693, + "top": 123, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74PZ3Vyi7yo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74PZ3VykX3M=", + "_parent": { + "$ref": "AAAAAAFk74PZ3Vyi7yo=" + }, + "model": { + "$ref": "AAAAAAFfKuxM+AnptLY=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 693, + "top": 108, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74PZ3Vyi7yo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74PZ3VylNUo=", + "_parent": { + "$ref": "AAAAAAFk74PZ3Vyi7yo=" + }, + "model": { + "$ref": "AAAAAAFfKuxM+AnptLY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 693, + "top": 153, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74PZ3Vyi7yo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74PZ2VyYHEI=" + }, + "tail": { + "$ref": "AAAAAAFk73whtFLUsGQ=" + }, + "lineStyle": 0, + "points": "578:144;808:144", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74PZ3Vyjh0Q=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74PZ3VykX3M=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74PZ3VylNUo=" + } + } + ] + }, + { + "_type": "UMLClassDiagram", + "_id": "AAAAAAFk74R9sVzuKF8=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Cache Diagram", + "visible": true, + "defaultDiagram": false, + "ownedViews": [ + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk74S2D10sNBo=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74S2D10tGY8=", + "_parent": { + "$ref": "AAAAAAFk74S2D10sNBo=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74S2D10uZrY=", + "_parent": { + "$ref": "AAAAAAFk74S2D10tGY8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 221, + "top": 21, + "width": 430, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74S2D10vbBY=", + "_parent": { + "$ref": "AAAAAAFk74S2D10tGY8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 221, + "top": 36, + "width": 430, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74S2D10wKvk=", + "_parent": { + "$ref": "AAAAAAFk74S2D10tGY8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 221, + "top": 51, + "width": 430, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74S2D10xdXw=", + "_parent": { + "$ref": "AAAAAAFk74S2D10tGY8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -90, + "top": -222, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 216, + "top": 16, + "width": 440, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74S2D10uZrY=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74S2D10vbBY=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74S2D10wKvk=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74S2D10xdXw=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74S2EF0y8/c=", + "_parent": { + "$ref": "AAAAAAFk74S2D10sNBo=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -45, + "top": -111, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74S2EF0zElg=", + "_parent": { + "$ref": "AAAAAAFk74S2D10sNBo=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74S2PV1SmAA=", + "_parent": { + "$ref": "AAAAAAFk74S2EF0zElg=" + }, + "model": { + "$ref": "AAAAAAFkzOhe6QsQ8iE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 221, + "top": 74, + "width": 454, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+queryImage(key, options, context, completionBlock): SDWebImageOperation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74S2PV1VBkU=", + "_parent": { + "$ref": "AAAAAAFk74S2EF0zElg=" + }, + "model": { + "$ref": "AAAAAAFkzOmFQhJb/sw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 221, + "top": 89, + "width": 454, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+store(image, imageData, key, cacheType, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74S2Pl1Yzjg=", + "_parent": { + "$ref": "AAAAAAFk74S2EF0zElg=" + }, + "model": { + "$ref": "AAAAAAFkzOpiQxehydI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 221, + "top": 104, + "width": 454, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeImage(key, cacheType, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74S2Pl1b6iE=", + "_parent": { + "$ref": "AAAAAAFk74S2EF0zElg=" + }, + "model": { + "$ref": "AAAAAAFkzOrxchsvmU0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 221, + "top": 119, + "width": 454, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+containsImage(key, cacheType, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74S2Pl1e0Ls=", + "_parent": { + "$ref": "AAAAAAFk74S2EF0zElg=" + }, + "model": { + "$ref": "AAAAAAFkzOvaYx+Z2C8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 221, + "top": 134, + "width": 454, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+clear(cacheType, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 216, + "top": 69, + "width": 464, + "height": 83, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74S2EF00n14=", + "_parent": { + "$ref": "AAAAAAFk74S2D10sNBo=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -45, + "top": -111, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74S2EF01ebs=", + "_parent": { + "$ref": "AAAAAAFk74S2D10sNBo=" + }, + "model": { + "$ref": "AAAAAAFkzOdOrAhsolg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -45, + "top": -111, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 216, + "top": 16, + "width": 464, + "height": 147, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74S2D10tGY8=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74S2EF0y8/c=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74S2EF0zElg=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74S2EF00n14=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74S2EF01ebs=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk74TWXl1irxo=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74TWXl1jmyU=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1irxo=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74TWXl1kPNc=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1jmyU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -726, + "top": -66, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74TWXl1l2bk=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1jmyU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 255, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74TWXl1m3w8=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1jmyU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 270, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74TWXl1n6mM=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1jmyU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -726, + "top": -66, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 280, + "top": 248, + "width": 424, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74TWXl1kPNc=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74TWXl1l2bk=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74TWXl1m3w8=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74TWXl1n6mM=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74TWXl1ogrQ=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1irxo=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74TWrl2TMtw=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ogrQ=" + }, + "model": { + "$ref": "AAAAAAFUkiFzJY5gThM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 293, + "width": 414, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedImageCache", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74TWr12WZqg=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ogrQ=" + }, + "model": { + "$ref": "AAAAAAFk0LaA7lthFIA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 308, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+config: SDImageCacheConfig", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74TWr12ZOOs=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ogrQ=" + }, + "model": { + "$ref": "AAAAAAFUmPDC7hpSvPQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 323, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+diskCachePath", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74TWsF2cTVM=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ogrQ=" + }, + "model": { + "$ref": "AAAAAAFUmPDhrRsNyCc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 338, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+additionalCachePathBlock", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 280, + "top": 288, + "width": 424, + "height": 68, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74TWXl1ps44=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1irxo=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWsF2fiS8=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFUmPHYnB7PNs4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 361, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(namespace, diskCacheDirectory, config)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWsV2i3dE=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFUmPTT0CgBzK8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 376, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cachePath(key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWsV2lFLg=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFUmPMOWiHsOa0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 391, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+store(image, imageData, key, toDisk, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWsl2ohsE=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFUmPMtQiKnVfM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 406, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+storeImage(image, key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWsl2r4Xg=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFk0NC0bOZw4VQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 421, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+storeImageData(imageData, key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWs12uuuA=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFk0NF3Z+sY0tc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 436, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+diskImageExists(key, completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWs12xLE0=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFk0NJKG+/90EA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 451, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+diskImageDataExists(key): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWs120LqM=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFk0NLcpfVc3Q8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 466, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+diskImageData(key): Data", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWs123Xtc=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFk0NOWwPpBKis=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 481, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+queryCacheOperation(key, options, context, doneBlock): NSOperation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWtF26lyY=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFUmPOk0iRaSME=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 496, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageFromMemoryCache(key): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWtF29iw0=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFUmPPBiSUVHSU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 511, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageFromDiskCache(key): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWtF3AgI0=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFk0NaQzAru2sk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 526, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+imageFromCache(key): UIImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWtV3DQ6g=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFUmPPiwSXQs7U=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 541, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeImage(key, fromDisk, completion)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWtV3GSlI=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFk0NfB0BJxwa0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 556, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeImageFromMemory(key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWtV3JW2o=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFk0NhSwxdz+po=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 571, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeImageFromDisk(key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWtl3MRKQ=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFUmPQzYSaLCQc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 586, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+clearMemory()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWtl3Pwko=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFUmPRYYSdGCZA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 601, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+clearDIsk(completion)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWtl3S0GI=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFUmPT4WSi8pg0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 616, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+deleteOldFiles(completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWt13V3VY=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFk0Nk9Zhzuux0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 631, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+getSize(): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWt13YP2A=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFk0NmTbx80+MQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 646, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+getDiskCount(): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74TWt13bsSs=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "model": { + "$ref": "AAAAAAFk0Nn28SF6Hq4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 661, + "width": 414, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+calculateSize(completionBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 280, + "top": 356, + "width": 424, + "height": 323, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74TWXl1qjz8=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1irxo=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -363, + "top": -33, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74TWXl1r8e8=", + "_parent": { + "$ref": "AAAAAAFk74TWXl1irxo=" + }, + "model": { + "$ref": "AAAAAAFUkh79WI34fB0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -363, + "top": -33, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 280, + "top": 248, + "width": 424, + "height": 431, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74TWXl1jmyU=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74TWXl1ogrQ=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74TWXl1ps44=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74TWXl1qjz8=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74TWXl1r8e8=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk74TWX11sHH8=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74TWX11tSJQ=", + "_parent": { + "$ref": "AAAAAAFk74TWX11sHH8=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 474, + "top": 198, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74TWX11sHH8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74TWYF1ulAY=", + "_parent": { + "$ref": "AAAAAAFk74TWX11sHH8=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 459, + "top": 198, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74TWX11sHH8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74TWYF1v1II=", + "_parent": { + "$ref": "AAAAAAFk74TWX11sHH8=" + }, + "model": { + "$ref": "AAAAAAFUmN83duYfrao=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 503, + "top": 199, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74TWX11sHH8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74S2D10sNBo=" + }, + "tail": { + "$ref": "AAAAAAFk74TWXl1irxo=" + }, + "lineStyle": 0, + "points": "489:248;489:162", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74TWX11tSJQ=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74TWYF1ulAY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74TWYF1v1II=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk74Tfvl3iKyU=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74Tfvl3jx4c=", + "_parent": { + "$ref": "AAAAAAFk74Tfvl3iKyU=" + }, + "model": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74Tfvl3kFy4=", + "_parent": { + "$ref": "AAAAAAFk74Tfvl3jx4c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1170, + "top": -282, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74Tfvl3lwhA=", + "_parent": { + "$ref": "AAAAAAFk74Tfvl3jx4c=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 255, + "width": 184, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCacheConfig", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74Tfvl3m/oY=", + "_parent": { + "$ref": "AAAAAAFk74Tfvl3jx4c=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 270, + "width": 184, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74Tfvl3n0OE=", + "_parent": { + "$ref": "AAAAAAFk74Tfvl3jx4c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1170, + "top": -282, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 784, + "top": 248, + "width": 194, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74Tfvl3kFy4=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74Tfvl3lwhA=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74Tfvl3m/oY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74Tfvl3n0OE=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74Tfvl3o0zg=", + "_parent": { + "$ref": "AAAAAAFk74Tfvl3iKyU=" + }, + "model": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74Tf6l4I80c=", + "_parent": { + "$ref": "AAAAAAFk74Tfvl3o0zg=" + }, + "model": { + "$ref": "AAAAAAFUmPBKVhghKWk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 293, + "width": 184, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+shouldDecompressImages", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74Tf6l4Lans=", + "_parent": { + "$ref": "AAAAAAFk74Tfvl3o0zg=" + }, + "model": { + "$ref": "AAAAAAFUmPBxrhjcaQc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 308, + "width": 184, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+shouldDisableiCloud", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74Tf6l4Ougg=", + "_parent": { + "$ref": "AAAAAAFk74Tfvl3o0zg=" + }, + "model": { + "$ref": "AAAAAAFUmPCLlRmXEPs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 323, + "width": 184, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+shouldCacheImagesInMemory", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74Tf614RfII=", + "_parent": { + "$ref": "AAAAAAFk74Tfvl3o0zg=" + }, + "model": { + "$ref": "AAAAAAFUmPD+pRvI9sU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 338, + "width": 184, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+maxCacheAge", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74Tf614UGjk=", + "_parent": { + "$ref": "AAAAAAFk74Tfvl3o0zg=" + }, + "model": { + "$ref": "AAAAAAFUmPEdRRyDmKo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 353, + "width": 184, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+maxCacheSize", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 784, + "top": 288, + "width": 194, + "height": 83, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74Tfvl3pynU=", + "_parent": { + "$ref": "AAAAAAFk74Tfvl3iKyU=" + }, + "model": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 784, + "top": 371, + "width": 194, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74Tfvl3qZDk=", + "_parent": { + "$ref": "AAAAAAFk74Tfvl3iKyU=" + }, + "model": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 585, + "top": -141, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74Tfv13rAQw=", + "_parent": { + "$ref": "AAAAAAFk74Tfvl3iKyU=" + }, + "model": { + "$ref": "AAAAAAFXmwGn6ZeqpYw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 585, + "top": -141, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 784, + "top": 248, + "width": 194, + "height": 133, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74Tfvl3jx4c=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74Tfvl3o0zg=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74Tfvl3pynU=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74Tfvl3qZDk=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74Tfv13rAQw=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk74Tlhl4YbQ4=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74Tlhl4ZeMA=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4YbQ4=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74Tlhl4aHyg=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4ZeMA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1680, + "top": 352, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74Tlhl4bB9M=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4ZeMA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 255, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCachesManager", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74Tlhl4chKM=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4ZeMA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 270, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74Tlhl4dePE=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4ZeMA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1680, + "top": 352, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 248, + "width": 210, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74Tlhl4aHyg=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74Tlhl4bB9M=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74Tlhl4chKM=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74Tlhl4dePE=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74Tlhl4ez0w=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4YbQ4=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74Tl2V5JpWU=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4ez0w=" + }, + "model": { + "$ref": "AAAAAAFk7ALOcGXu/S8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 293, + "width": 200, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedManager", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74Tl2V5MDDI=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4ez0w=" + }, + "model": { + "$ref": "AAAAAAFk7AOZr28Bcso=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 308, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+caches: Array ", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74Tl2V5PCy4=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4ez0w=" + }, + "model": { + "$ref": "AAAAAAFk7AMCg2fWSP0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 323, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+queryOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74Tl2l5SINk=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4ez0w=" + }, + "model": { + "$ref": "AAAAAAFk7AMe/WlFG7c=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 338, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+storeOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74Tl2l5VhWk=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4ez0w=" + }, + "model": { + "$ref": "AAAAAAFk7ANGZ2q0x2Q=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 353, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74Tl2l5Ybiw=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4ez0w=" + }, + "model": { + "$ref": "AAAAAAFk7ANfz2wjKJg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 368, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+containsOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74Tl215bj+U=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4ez0w=" + }, + "model": { + "$ref": "AAAAAAFk7AN7JG2S4JE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 383, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+clearOperationPolicy", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 288, + "width": 210, + "height": 113, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74Tlhl4fwYQ=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4YbQ4=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74Tl215eQwk=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4fwYQ=" + }, + "model": { + "$ref": "AAAAAAFk7AQw/nZyZkk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 406, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+addCache()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74Tl3F5hCAo=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4fwYQ=" + }, + "model": { + "$ref": "AAAAAAFk7ARL1nfhIfg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 421, + "width": 200, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeCache()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 401, + "width": 210, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74Tlhl4gKNA=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4YbQ4=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -840, + "top": 176, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74Tlhl4hXMU=", + "_parent": { + "$ref": "AAAAAAFk74Tlhl4YbQ4=" + }, + "model": { + "$ref": "AAAAAAFk7AHuD1yFB/0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -840, + "top": 176, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 248, + "width": 210, + "height": 191, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74Tlhl4ZeMA=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74Tlhl4ez0w=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74Tlhl4fwYQ=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74Tlhl4gKNA=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74Tlhl4hXMU=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk74Tlh14i1QY=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk7Ae0KaF0uoo=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74Tlh14jeyM=", + "_parent": { + "$ref": "AAAAAAFk74Tlh14i1QY=" + }, + "model": { + "$ref": "AAAAAAFk7Ae0KaF0uoo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 112, + "top": 132, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74Tlh14i1QY=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74Tlh14kmKg=", + "_parent": { + "$ref": "AAAAAAFk74Tlh14i1QY=" + }, + "model": { + "$ref": "AAAAAAFk7Ae0KaF0uoo=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 112, + "top": 117, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74Tlh14i1QY=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74Tlh14lkf0=", + "_parent": { + "$ref": "AAAAAAFk74Tlh14i1QY=" + }, + "model": { + "$ref": "AAAAAAFk7Ae0KaF0uoo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 112, + "top": 162, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74Tlh14i1QY=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74S2D10sNBo=" + }, + "tail": { + "$ref": "AAAAAAFk74Tlhl4YbQ4=" + }, + "lineStyle": 0, + "points": "112:248;112:153;216:153", + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74Tlh14jeyM=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74Tlh14kmKg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74Tlh14lkf0=" + } + }, + { + "_type": "UMLEnumerationView", + "_id": "AAAAAAFk74Uaf15oxwI=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74Uaf15pEeI=", + "_parent": { + "$ref": "AAAAAAFk74Uaf15oxwI=" + }, + "model": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74Uaf15qrB8=", + "_parent": { + "$ref": "AAAAAAFk74Uaf15pEeI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 21, + "width": 143, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«enumeration»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74Uaf15r1bs=", + "_parent": { + "$ref": "AAAAAAFk74Uaf15pEeI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 36, + "width": 143, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCacheOptions", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74Uaf15sCNg=", + "_parent": { + "$ref": "AAAAAAFk74Uaf15pEeI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 51, + "width": 143, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74Uaf15tfXA=", + "_parent": { + "$ref": "AAAAAAFk74Uaf15pEeI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 856, + "top": -1252, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 784, + "top": 16, + "width": 153, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74Uaf15qrB8=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74Uaf15r1bs=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74Uaf15sCNg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74Uaf15tfXA=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74Uaf15umec=", + "_parent": { + "$ref": "AAAAAAFk74Uaf15oxwI=" + }, + "model": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 428, + "top": -626, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74Uaf15vhIA=", + "_parent": { + "$ref": "AAAAAAFk74Uaf15oxwI=" + }, + "model": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 428, + "top": -626, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74UagF5w32k=", + "_parent": { + "$ref": "AAAAAAFk74Uaf15oxwI=" + }, + "model": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 428, + "top": -626, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74UagF5x6ro=", + "_parent": { + "$ref": "AAAAAAFk74Uaf15oxwI=" + }, + "model": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 428, + "top": -626, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLEnumerationLiteralCompartmentView", + "_id": "AAAAAAFk74UagF5yxMQ=", + "_parent": { + "$ref": "AAAAAAFk74Uaf15oxwI=" + }, + "model": { + "$ref": "AAAAAAFk0MPrmZLdeGs=" + }, + "subViews": [ + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk74UarF6SEsc=", + "_parent": { + "$ref": "AAAAAAFk74UagF5yxMQ=" + }, + "model": { + "$ref": "AAAAAAFk0MQrOpM/jI0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 74, + "width": 143, + "height": 13, + "autoResize": false, + "underline": false, + "text": "queryMemoryData", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk74UarV6VHkc=", + "_parent": { + "$ref": "AAAAAAFk74UagF5yxMQ=" + }, + "model": { + "$ref": "AAAAAAFk0MRCXJO7Xl0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 89, + "width": 143, + "height": 13, + "autoResize": false, + "underline": false, + "text": "queryMemoryDataSync", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk74UarV6YH/w=", + "_parent": { + "$ref": "AAAAAAFk74UagF5yxMQ=" + }, + "model": { + "$ref": "AAAAAAFk0MRaJJQ3LUY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 104, + "width": 143, + "height": 13, + "autoResize": false, + "underline": false, + "text": "queryDiskDataSync", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk74UarV6bGjE=", + "_parent": { + "$ref": "AAAAAAFk74UagF5yxMQ=" + }, + "model": { + "$ref": "AAAAAAFk0MR51JSzxio=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 119, + "width": 143, + "height": 13, + "autoResize": false, + "underline": false, + "text": "scaleDownLargeImages", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk74Uarl6enjQ=", + "_parent": { + "$ref": "AAAAAAFk74UagF5yxMQ=" + }, + "model": { + "$ref": "AAAAAAFk0MSZXZUvhjA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 134, + "width": 143, + "height": 13, + "autoResize": false, + "underline": false, + "text": "avoidDecodeImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk74Uarl6h03Q=", + "_parent": { + "$ref": "AAAAAAFk74UagF5yxMQ=" + }, + "model": { + "$ref": "AAAAAAFk0MS2hZWrSIM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 149, + "width": 143, + "height": 13, + "autoResize": false, + "underline": false, + "text": "decodeFirstFrameOnly", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk74Uarl6kdNg=", + "_parent": { + "$ref": "AAAAAAFk74UagF5yxMQ=" + }, + "model": { + "$ref": "AAAAAAFk0MTONZYnA3o=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 789, + "top": 164, + "width": 143, + "height": 13, + "autoResize": false, + "underline": false, + "text": "preloadAllFrames", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 784, + "top": 69, + "width": 153, + "height": 113, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 784, + "top": 16, + "width": 153, + "height": 166, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74Uaf15pEeI=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74Uaf15umec=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74Uaf15vhIA=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74UagF5w32k=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74UagF5x6ro=" + }, + "suppressLiterals": false, + "enumerationLiteralCompartment": { + "$ref": "AAAAAAFk74UagF5yxMQ=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk74VTml6o1so=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74VTm16pfmA=", + "_parent": { + "$ref": "AAAAAAFk74VTml6o1so=" + }, + "model": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74VTm16qvkM=", + "_parent": { + "$ref": "AAAAAAFk74VTm16pfmA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 509, + "top": 749, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74VTm16rz58=", + "_parent": { + "$ref": "AAAAAAFk74VTm16pfmA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 509, + "top": 764, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDDiskCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74VTm16s+Us=", + "_parent": { + "$ref": "AAAAAAFk74VTm16pfmA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 509, + "top": 779, + "width": 128, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74VTm16tfE4=", + "_parent": { + "$ref": "AAAAAAFk74VTm16pfmA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -574, + "top": -62, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 504, + "top": 744, + "width": 138, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74VTm16qvkM=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74VTm16rz58=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74VTm16s+Us=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74VTm16tfE4=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74VTm16uARA=", + "_parent": { + "$ref": "AAAAAAFk74VTml6o1so=" + }, + "model": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -287, + "top": -31, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74VTm16v+bk=", + "_parent": { + "$ref": "AAAAAAFk74VTml6o1so=" + }, + "model": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VT8F7xeJg=", + "_parent": { + "$ref": "AAAAAAFk74VTm16v+bk=" + }, + "model": { + "$ref": "AAAAAAFk0Ol/z4IFWS0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 509, + "top": 802, + "width": 152, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(cachePath, config)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VT8F70zXU=", + "_parent": { + "$ref": "AAAAAAFk74VTm16v+bk=" + }, + "model": { + "$ref": "AAAAAAFk0OnkkIWQSuA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 509, + "top": 817, + "width": 152, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+containsData(key): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VT8F73z9Y=", + "_parent": { + "$ref": "AAAAAAFk74VTm16v+bk=" + }, + "model": { + "$ref": "AAAAAAFk0OpCIYkbyn4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 509, + "top": 832, + "width": 152, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+data(key): Data", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VT8V76xE0=", + "_parent": { + "$ref": "AAAAAAFk74VTm16v+bk=" + }, + "model": { + "$ref": "AAAAAAFk0OrYDIym0yM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 509, + "top": 847, + "width": 152, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+setData(data, key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VT8V79IMw=", + "_parent": { + "$ref": "AAAAAAFk74VTm16v+bk=" + }, + "model": { + "$ref": "AAAAAAFk0OsjbY/ujGE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 509, + "top": 862, + "width": 152, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeData(key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VT8V8ATpU=", + "_parent": { + "$ref": "AAAAAAFk74VTm16v+bk=" + }, + "model": { + "$ref": "AAAAAAFk0OtXrZIqqoc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 509, + "top": 877, + "width": 152, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeAllData()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VT8l8Dyak=", + "_parent": { + "$ref": "AAAAAAFk74VTm16v+bk=" + }, + "model": { + "$ref": "AAAAAAFk0Otz15O9b20=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 509, + "top": 892, + "width": 152, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeExpiredData()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VT9F8GN74=", + "_parent": { + "$ref": "AAAAAAFk74VTm16v+bk=" + }, + "model": { + "$ref": "AAAAAAFk0OuYl5VQkGk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 509, + "top": 907, + "width": 152, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cachePath(key): String", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VT9F8JDGM=", + "_parent": { + "$ref": "AAAAAAFk74VTm16v+bk=" + }, + "model": { + "$ref": "AAAAAAFk0Ovfd5eMoXg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 509, + "top": 922, + "width": 152, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+totalCount(): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VT9V8MwrU=", + "_parent": { + "$ref": "AAAAAAFk74VTm16v+bk=" + }, + "model": { + "$ref": "AAAAAAFk0OxV6pu94G8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 509, + "top": 937, + "width": 152, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+totalSize(): UInt", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 504, + "top": 797, + "width": 162, + "height": 158, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74VTm16w7mQ=", + "_parent": { + "$ref": "AAAAAAFk74VTml6o1so=" + }, + "model": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -287, + "top": -31, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74VTm16xVYQ=", + "_parent": { + "$ref": "AAAAAAFk74VTml6o1so=" + }, + "model": { + "$ref": "AAAAAAFk0OkMLX851sM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -287, + "top": -31, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 504, + "top": 744, + "width": 162, + "height": 222, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74VTm16pfmA=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74VTm16uARA=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74VTm16v+bk=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74VTm16w7mQ=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74VTm16xVYQ=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk74VTnF6yRXw=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74VTnF6zz9Q=", + "_parent": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 577, + "top": 704, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74VTnF60nrM=", + "_parent": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 562, + "top": 704, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74VTnF61AMU=", + "_parent": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO3R8M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 606, + "top": 705, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74VTnF62GeU=", + "_parent": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 577, + "top": 712, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74VTnF63Uvw=", + "_parent": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 563, + "top": 709, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74VTnF64XLQ=", + "_parent": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 604, + "top": 716, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74VTnF65I1c=", + "_parent": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 577, + "top": 697, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74VTnF66ntA=", + "_parent": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 563, + "top": 700, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74VTnF675qo=", + "_parent": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 604, + "top": 693, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk74VTnF68uLE=", + "_parent": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO4X9g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk74VTnV69UmE=", + "_parent": { + "$ref": "AAAAAAFk74VTnF6yRXw=" + }, + "model": { + "$ref": "AAAAAAFXmwYAOLO5TNo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74TWXl1irxo=" + }, + "tail": { + "$ref": "AAAAAAFk74VTml6o1so=" + }, + "lineStyle": 0, + "points": "592:744;592:678", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74VTnF6zz9Q=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74VTnF60nrM=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74VTnF61AMU=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk74VTnF62GeU=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk74VTnF63Uvw=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk74VTnF64XLQ=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk74VTnF65I1c=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk74VTnF66ntA=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk74VTnF675qo=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk74VTnF68uLE=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk74VTnV69UmE=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk74VZ118qqLI=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74VZ118rTS8=", + "_parent": { + "$ref": "AAAAAAFk74VZ118qqLI=" + }, + "model": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74VZ118sdtg=", + "_parent": { + "$ref": "AAAAAAFk74VZ118rTS8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 749, + "width": 145, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74VZ2F8tBV0=", + "_parent": { + "$ref": "AAAAAAFk74VZ118rTS8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 764, + "width": 145, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDMemoryCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74VZ2F8u9GA=", + "_parent": { + "$ref": "AAAAAAFk74VZ118rTS8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 779, + "width": 145, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74VZ2F8vOd4=", + "_parent": { + "$ref": "AAAAAAFk74VZ118rTS8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -802, + "top": -290, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 312, + "top": 744, + "width": 155, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74VZ118sdtg=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74VZ2F8tBV0=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74VZ2F8u9GA=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74VZ2F8vOd4=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74VZ2F8ww0E=", + "_parent": { + "$ref": "AAAAAAFk74VZ118qqLI=" + }, + "model": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -401, + "top": -145, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74VZ2F8xEsM=", + "_parent": { + "$ref": "AAAAAAFk74VZ118qqLI=" + }, + "model": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VaBV9TjjY=", + "_parent": { + "$ref": "AAAAAAFk74VZ2F8xEsM=" + }, + "model": { + "$ref": "AAAAAAFk0OSfa2QT4IA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 802, + "width": 169, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(config)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VaBV9WfDU=", + "_parent": { + "$ref": "AAAAAAFk74VZ2F8xEsM=" + }, + "model": { + "$ref": "AAAAAAFk0OTdZGUCETU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 817, + "width": 169, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+object(key)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VaBl9ZmxU=", + "_parent": { + "$ref": "AAAAAAFk74VZ2F8xEsM=" + }, + "model": { + "$ref": "AAAAAAFk0OUR7WXxHho=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 832, + "width": 169, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+setObject(object, key, cost)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VaBl9cK/E=", + "_parent": { + "$ref": "AAAAAAFk74VZ2F8xEsM=" + }, + "model": { + "$ref": "AAAAAAFk0OWj72fwP7o=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 847, + "width": 169, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeObject(object)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74VaBl9fkIQ=", + "_parent": { + "$ref": "AAAAAAFk74VZ2F8xEsM=" + }, + "model": { + "$ref": "AAAAAAFk0OXRGGjfriQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 862, + "width": 169, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeAllObjects()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 312, + "top": 797, + "width": 179, + "height": 83, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74VZ2F8yZ1Q=", + "_parent": { + "$ref": "AAAAAAFk74VZ118qqLI=" + }, + "model": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -401, + "top": -145, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74VZ2F8zeA8=", + "_parent": { + "$ref": "AAAAAAFk74VZ118qqLI=" + }, + "model": { + "$ref": "AAAAAAFk0OQoUmOmW5c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -401, + "top": -145, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 312, + "top": 744, + "width": 179, + "height": 147, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74VZ118rTS8=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74VZ2F8ww0E=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74VZ2F8xEsM=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74VZ2F8yZ1Q=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74VZ2F8zeA8=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk74WD6F9ykYg=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk0Oy3g5480kU=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74WD6F9zDBU=", + "_parent": { + "$ref": "AAAAAAFk74WD6F9ykYg=" + }, + "model": { + "$ref": "AAAAAAFk0Oy3g5480kU=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74WD6V90j4k=", + "_parent": { + "$ref": "AAAAAAFk74WD6F9zDBU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -856, + "top": 220, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74WD6V91ZUc=", + "_parent": { + "$ref": "AAAAAAFk74WD6F9zDBU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 525, + "top": 1015, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDDiskCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74WD6V92OOw=", + "_parent": { + "$ref": "AAAAAAFk74WD6F9zDBU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 525, + "top": 1030, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74WD6V93Iak=", + "_parent": { + "$ref": "AAAAAAFk74WD6F9zDBU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -856, + "top": 220, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 520, + "top": 1008, + "width": 128, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74WD6V90j4k=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74WD6V91ZUc=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74WD6V92OOw=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74WD6V93Iak=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74WD6V94r+g=", + "_parent": { + "$ref": "AAAAAAFk74WD6F9ykYg=" + }, + "model": { + "$ref": "AAAAAAFk0Oy3g5480kU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 520, + "top": 1048, + "width": 128, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74WD6V95CEo=", + "_parent": { + "$ref": "AAAAAAFk74WD6F9ykYg=" + }, + "model": { + "$ref": "AAAAAAFk0Oy3g5480kU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 520, + "top": 1058, + "width": 128, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74WD6V962xY=", + "_parent": { + "$ref": "AAAAAAFk74WD6F9ykYg=" + }, + "model": { + "$ref": "AAAAAAFk0Oy3g5480kU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -428, + "top": 110, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74WD6V97H6U=", + "_parent": { + "$ref": "AAAAAAFk74WD6F9ykYg=" + }, + "model": { + "$ref": "AAAAAAFk0Oy3g5480kU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -428, + "top": 110, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 520, + "top": 1008, + "width": 128, + "height": 60, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74WD6F9zDBU=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74WD6V94r+g=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74WD6V95CEo=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74WD6V962xY=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74WD6V97H6U=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk74WD6V98/Zs=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74WD6V99HY0=", + "_parent": { + "$ref": "AAAAAAFk74WD6V98/Zs=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 568, + "top": 979, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74WD6V98/Zs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74WD6l9+lCM=", + "_parent": { + "$ref": "AAAAAAFk74WD6V98/Zs=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 553, + "top": 979, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74WD6V98/Zs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74WD6l9/3oA=", + "_parent": { + "$ref": "AAAAAAFk74WD6V98/Zs=" + }, + "model": { + "$ref": "AAAAAAFUmORm3fAwE60=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 597, + "top": 980, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74WD6V98/Zs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74VTml6o1so=" + }, + "tail": { + "$ref": "AAAAAAFk74WD6F9ykYg=" + }, + "lineStyle": 1, + "points": "583:1007;583:966", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74WD6V99HY0=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74WD6l9+lCM=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74WD6l9/3oA=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk74WmIV+5ur0=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74WmIV+6LKk=", + "_parent": { + "$ref": "AAAAAAFk74WmIV+5ur0=" + }, + "model": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74WmIV+7/xo=", + "_parent": { + "$ref": "AAAAAAFk74WmIV+6LKk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -926, + "top": 10, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74WmIV+8600=", + "_parent": { + "$ref": "AAAAAAFk74WmIV+6LKk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 333, + "top": 1015, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDMemoryCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74WmIV+9yk0=", + "_parent": { + "$ref": "AAAAAAFk74WmIV+6LKk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 333, + "top": 1030, + "width": 118, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74WmIV++Q8g=", + "_parent": { + "$ref": "AAAAAAFk74WmIV+6LKk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -926, + "top": 10, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 328, + "top": 1008, + "width": 128, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74WmIV+7/xo=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74WmIV+8600=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74WmIV+9yk0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74WmIV++Q8g=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74WmIV+/XzA=", + "_parent": { + "$ref": "AAAAAAFk74WmIV+5ur0=" + }, + "model": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 328, + "top": 1048, + "width": 128, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74WmIV/AdBY=", + "_parent": { + "$ref": "AAAAAAFk74WmIV+5ur0=" + }, + "model": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 328, + "top": 1058, + "width": 128, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74WmIV/BMOA=", + "_parent": { + "$ref": "AAAAAAFk74WmIV+5ur0=" + }, + "model": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -463, + "top": 5, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74WmIV/CxT4=", + "_parent": { + "$ref": "AAAAAAFk74WmIV+5ur0=" + }, + "model": { + "$ref": "AAAAAAFk0Oaeq24jZhk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -463, + "top": 5, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 328, + "top": 1008, + "width": 128, + "height": 60, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74WmIV+6LKk=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74WmIV+/XzA=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74WmIV/AdBY=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74WmIV/BMOA=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74WmIV/CxT4=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk74XBwV/y5Aw=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk0ObxVHApLxs=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74XBwV/zwFo=", + "_parent": { + "$ref": "AAAAAAFk74XBwV/y5Aw=" + }, + "model": { + "$ref": "AAAAAAFk0ObxVHApLxs=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74XBwV/0F68=", + "_parent": { + "$ref": "AAAAAAFk74XBwV/zwFo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -760, + "top": 120, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74XBwl/1t/E=", + "_parent": { + "$ref": "AAAAAAFk74XBwV/zwFo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 165, + "top": 1015, + "width": 102, + "height": 13, + "autoResize": false, + "underline": false, + "text": "NSCache", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74XBwl/2j+s=", + "_parent": { + "$ref": "AAAAAAFk74XBwV/zwFo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 165, + "top": 1030, + "width": 102, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from Foundation)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74XBwl/36FQ=", + "_parent": { + "$ref": "AAAAAAFk74XBwV/zwFo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -760, + "top": 120, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 160, + "top": 1008, + "width": 112, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74XBwV/0F68=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74XBwl/1t/E=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74XBwl/2j+s=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74XBwl/36FQ=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74XBwl/4e/Q=", + "_parent": { + "$ref": "AAAAAAFk74XBwV/y5Aw=" + }, + "model": { + "$ref": "AAAAAAFk0ObxVHApLxs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 160, + "top": 1048, + "width": 112, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74XBwl/55Ds=", + "_parent": { + "$ref": "AAAAAAFk74XBwV/y5Aw=" + }, + "model": { + "$ref": "AAAAAAFk0ObxVHApLxs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 160, + "top": 1058, + "width": 112, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74XBwl/6+eo=", + "_parent": { + "$ref": "AAAAAAFk74XBwV/y5Aw=" + }, + "model": { + "$ref": "AAAAAAFk0ObxVHApLxs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -380, + "top": 60, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74XBwl/710w=", + "_parent": { + "$ref": "AAAAAAFk74XBwV/y5Aw=" + }, + "model": { + "$ref": "AAAAAAFk0ObxVHApLxs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -380, + "top": 60, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 160, + "top": 1008, + "width": 112, + "height": 60, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74XBwV/zwFo=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74XBwl/4e/Q=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74XBwl/55Ds=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74XBwl/6+eo=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74XBwl/710w=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAFk74XBwl/87Xo=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74XBw1/9DUE=", + "_parent": { + "$ref": "AAAAAAFk74XBwl/87Xo=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 298, + "top": 1046, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74XBwl/87Xo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74XBw1/+Ttg=", + "_parent": { + "$ref": "AAAAAAFk74XBwl/87Xo=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 298, + "top": 1061, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74XBwl/87Xo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74XBw1//y4o=", + "_parent": { + "$ref": "AAAAAAFk74XBwl/87Xo=" + }, + "model": { + "$ref": "AAAAAAFfKutJugVRytg=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 299, + "top": 1016, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74XBwl/87Xo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74XBwV/y5Aw=" + }, + "tail": { + "$ref": "AAAAAAFk74WmIV+5ur0=" + }, + "lineStyle": 1, + "points": "327:1037;272:1037", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74XBw1/9DUE=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74XBw1/+Ttg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74XBw1//y4o=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk74cA9WHIBjQ=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk74cA82HEn7s=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74cA9WHJ8Ys=", + "_parent": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "model": { + "$ref": "AAAAAAFk74cA82HEn7s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 742, + "top": 313, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74cA9WHKFGU=", + "_parent": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "model": { + "$ref": "AAAAAAFk74cA82HEn7s=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 742, + "top": 328, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74cA9WHLAJ4=", + "_parent": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "model": { + "$ref": "AAAAAAFk74cA82HEn7s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 743, + "top": 283, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74cA9WHME44=", + "_parent": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "model": { + "$ref": "AAAAAAFk74cA82HFdlQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 758, + "top": 312, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74cA9WHNyvo=", + "_parent": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "model": { + "$ref": "AAAAAAFk74cA82HFdlQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 755, + "top": 326, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74cA9WHORC0=", + "_parent": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "model": { + "$ref": "AAAAAAFk74cA82HFdlQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 762, + "top": 285, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74cA9mHPiKU=", + "_parent": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "model": { + "$ref": "AAAAAAFk74cA82HGTl0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 728, + "top": 312, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74cA9mHQnIc=", + "_parent": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "model": { + "$ref": "AAAAAAFk74cA82HGTl0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 731, + "top": 326, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74cA9mHR5kA=", + "_parent": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "model": { + "$ref": "AAAAAAFk74cA82HGTl0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 724, + "top": 285, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk74cA9mHSKeQ=", + "_parent": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "model": { + "$ref": "AAAAAAFk74cA82HFdlQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk74cA9mHTW5c=", + "_parent": { + "$ref": "AAAAAAFk74cA9WHIBjQ=" + }, + "model": { + "$ref": "AAAAAAFk74cA82HGTl0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74TWXl1irxo=" + }, + "tail": { + "$ref": "AAAAAAFk74Tfvl3iKyU=" + }, + "lineStyle": 0, + "points": "784:304;703:304", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74cA9WHJ8Ys=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74cA9WHKFGU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74cA9WHLAJ4=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk74cA9WHME44=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk74cA9WHNyvo=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk74cA9WHORC0=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk74cA9mHPiKU=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk74cA9mHQnIc=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk74cA9mHR5kA=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk74cA9mHSKeQ=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk74cA9mHTW5c=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk74en/mM9oBI=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk74en/WM7cFM=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74en/mM+zng=", + "_parent": { + "$ref": "AAAAAAFk74en/mM9oBI=" + }, + "model": { + "$ref": "AAAAAAFk74en/WM7cFM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 731, + "top": 75, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74en/mM9oBI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74en/mM/sBk=", + "_parent": { + "$ref": "AAAAAAFk74en/mM9oBI=" + }, + "model": { + "$ref": "AAAAAAFk74en/WM7cFM=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 731, + "top": 60, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74en/mM9oBI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74en/mNA4go=", + "_parent": { + "$ref": "AAAAAAFk74en/mM9oBI=" + }, + "model": { + "$ref": "AAAAAAFk74en/WM7cFM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 731, + "top": 105, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74en/mM9oBI=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74Uaf15oxwI=" + }, + "tail": { + "$ref": "AAAAAAFk74S2D10sNBo=" + }, + "lineStyle": 0, + "points": "679:96;784:96", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74en/mM+zng=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74en/mM/sBk=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74en/mNA4go=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk74e4zmN4SkQ=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk74e4zmN2kbM=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74e4z2N5Bn8=", + "_parent": { + "$ref": "AAAAAAFk74e4zmN4SkQ=" + }, + "model": { + "$ref": "AAAAAAFk74e4zmN2kbM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 732, + "top": 196, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74e4zmN4SkQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74e4z2N6w9Q=", + "_parent": { + "$ref": "AAAAAAFk74e4zmN4SkQ=" + }, + "model": { + "$ref": "AAAAAAFk74e4zmN2kbM=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 722, + "top": 185, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74e4zmN4SkQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74e4z2N7ASM=", + "_parent": { + "$ref": "AAAAAAFk74e4zmN4SkQ=" + }, + "model": { + "$ref": "AAAAAAFk74e4zmN2kbM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 753, + "top": 217, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74e4zmN4SkQ=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74Uaf15oxwI=" + }, + "tail": { + "$ref": "AAAAAAFk74TWXl1irxo=" + }, + "lineStyle": 1, + "points": "704:252;783:174", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74e4z2N5Bn8=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74e4z2N6w9Q=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74e4z2N7ASM=" + } + }, + { + "_type": "UMLEnumerationView", + "_id": "AAAAAAFk74gVyWQT4eE=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk7ATKAnkUjt4=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74gVyWQUQzU=", + "_parent": { + "$ref": "AAAAAAFk74gVyWQT4eE=" + }, + "model": { + "$ref": "AAAAAAFk7ATKAnkUjt4=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74gVymQVaRA=", + "_parent": { + "$ref": "AAAAAAFk74gVyWQUQzU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 477, + "width": 254, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«enumeration»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74gVymQWUc0=", + "_parent": { + "$ref": "AAAAAAFk74gVyWQUQzU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 492, + "width": 254, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageCachesManagerOperationPolicy", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74gVymQX9vg=", + "_parent": { + "$ref": "AAAAAAFk74gVyWQUQzU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 507, + "width": 254, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74gVymQYcsY=", + "_parent": { + "$ref": "AAAAAAFk74gVyWQUQzU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -192, + "top": -58, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 472, + "width": 264, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74gVymQVaRA=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74gVymQWUc0=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74gVymQX9vg=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74gVymQYcsY=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74gVymQZq+I=", + "_parent": { + "$ref": "AAAAAAFk74gVyWQT4eE=" + }, + "model": { + "$ref": "AAAAAAFk7ATKAnkUjt4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -96, + "top": -29, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74gVymQa7qI=", + "_parent": { + "$ref": "AAAAAAFk74gVyWQT4eE=" + }, + "model": { + "$ref": "AAAAAAFk7ATKAnkUjt4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -96, + "top": -29, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74gVymQbiU4=", + "_parent": { + "$ref": "AAAAAAFk74gVyWQT4eE=" + }, + "model": { + "$ref": "AAAAAAFk7ATKAnkUjt4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -96, + "top": -29, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74gVy2Qc6xc=", + "_parent": { + "$ref": "AAAAAAFk74gVyWQT4eE=" + }, + "model": { + "$ref": "AAAAAAFk7ATKAnkUjt4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -96, + "top": -29, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLEnumerationLiteralCompartmentView", + "_id": "AAAAAAFk74gVy2Qdmv8=", + "_parent": { + "$ref": "AAAAAAFk74gVyWQT4eE=" + }, + "model": { + "$ref": "AAAAAAFk7ATKAnkUjt4=" + }, + "subViews": [ + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk74gV22RDdbA=", + "_parent": { + "$ref": "AAAAAAFk74gVy2Qdmv8=" + }, + "model": { + "$ref": "AAAAAAFk7AU1fnui68s=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 530, + "width": 254, + "height": 13, + "autoResize": false, + "underline": false, + "text": "serial", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk74gV3GRGZtc=", + "_parent": { + "$ref": "AAAAAAFk74gVy2Qdmv8=" + }, + "model": { + "$ref": "AAAAAAFk7AVOan0RTug=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 545, + "width": 254, + "height": 13, + "autoResize": false, + "underline": false, + "text": "concurrent", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk74gV3GRJYdk=", + "_parent": { + "$ref": "AAAAAAFk74gVy2Qdmv8=" + }, + "model": { + "$ref": "AAAAAAFk7AVno36AYek=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 560, + "width": 254, + "height": 13, + "autoResize": false, + "underline": false, + "text": "highestOnly", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk74gV3WRMvmY=", + "_parent": { + "$ref": "AAAAAAFk74gVy2Qdmv8=" + }, + "model": { + "$ref": "AAAAAAFk7AV+An/vm7g=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 13, + "top": 575, + "width": 254, + "height": 13, + "autoResize": false, + "underline": false, + "text": "lowestOnly", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 8, + "top": 525, + "width": 264, + "height": 68, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 8, + "top": 472, + "width": 264, + "height": 121, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74gVyWQUQzU=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74gVymQZq+I=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74gVymQa7qI=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74gVymQbiU4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74gVy2Qc6xc=" + }, + "suppressLiterals": false, + "enumerationLiteralCompartment": { + "$ref": "AAAAAAFk74gVy2Qdmv8=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk74icCGYwssk=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk74icCGYuXpY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74icCGYxnSE=", + "_parent": { + "$ref": "AAAAAAFk74icCGYwssk=" + }, + "model": { + "$ref": "AAAAAAFk74icCGYuXpY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 140, + "top": 448, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74icCGYwssk=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74icCWYy4lo=", + "_parent": { + "$ref": "AAAAAAFk74icCGYwssk=" + }, + "model": { + "$ref": "AAAAAAFk74icCGYuXpY=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 155, + "top": 448, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74icCGYwssk=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74icCWYz5ek=", + "_parent": { + "$ref": "AAAAAAFk74icCGYwssk=" + }, + "model": { + "$ref": "AAAAAAFk74icCGYuXpY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 111, + "top": 449, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74icCGYwssk=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74gVyWQT4eE=" + }, + "tail": { + "$ref": "AAAAAAFk74Tlhl4YbQ4=" + }, + "lineStyle": 0, + "points": "126:438;126:472", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74icCGYxnSE=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74icCWYy4lo=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74icCWYz5ek=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk74lfE2kriJo=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk74lfE2kn7IU=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74lfFGksgz8=", + "_parent": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "model": { + "$ref": "AAAAAAFk74lfE2kn7IU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 385, + "top": 704, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74lfFGktWfU=", + "_parent": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "model": { + "$ref": "AAAAAAFk74lfE2kn7IU=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 370, + "top": 704, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74lfFGkuLW0=", + "_parent": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "model": { + "$ref": "AAAAAAFk74lfE2kn7IU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 414, + "top": 705, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74lfFGkvimI=", + "_parent": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "model": { + "$ref": "AAAAAAFk74lfE2kond4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 385, + "top": 712, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74lfFGkwqcw=", + "_parent": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "model": { + "$ref": "AAAAAAFk74lfE2kond4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 371, + "top": 709, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74lfFGkxEOE=", + "_parent": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "model": { + "$ref": "AAAAAAFk74lfE2kond4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 412, + "top": 716, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74lfFGky+5k=", + "_parent": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "model": { + "$ref": "AAAAAAFk74lfE2kppRA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 385, + "top": 697, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74lfFGkzyK0=", + "_parent": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "model": { + "$ref": "AAAAAAFk74lfE2kppRA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 371, + "top": 700, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74lfFGk0SrM=", + "_parent": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "model": { + "$ref": "AAAAAAFk74lfE2kppRA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 412, + "top": 693, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk74lfFGk1Ksc=", + "_parent": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "model": { + "$ref": "AAAAAAFk74lfE2kond4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk74lfFGk2ezs=", + "_parent": { + "$ref": "AAAAAAFk74lfE2kriJo=" + }, + "model": { + "$ref": "AAAAAAFk74lfE2kppRA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 40, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74TWXl1irxo=" + }, + "tail": { + "$ref": "AAAAAAFk74VZ118qqLI=" + }, + "lineStyle": 0, + "points": "400:744;400:678", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74lfFGksgz8=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74lfFGktWfU=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74lfFGkuLW0=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk74lfFGkvimI=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk74lfFGkwqcw=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk74lfFGkxEOE=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk74lfFGky+5k=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk74lfFGkzyK0=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk74lfFGk0SrM=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk74lfFGk1Ksc=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk74lfFGk2ezs=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk74n+cGzz4x8=", + "_parent": { + "$ref": "AAAAAAFk74R9sVzuKF8=" + }, + "model": { + "$ref": "AAAAAAFk74n+b2zyIZQ=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74n+cGz0sRs=", + "_parent": { + "$ref": "AAAAAAFk74n+cGzz4x8=" + }, + "model": { + "$ref": "AAAAAAFk74n+b2zyIZQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 375, + "top": 942, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74n+cGzz4x8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74n+cGz1144=", + "_parent": { + "$ref": "AAAAAAFk74n+cGzz4x8=" + }, + "model": { + "$ref": "AAAAAAFk74n+b2zyIZQ=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 360, + "top": 942, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74n+cGzz4x8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74n+cGz2QC8=", + "_parent": { + "$ref": "AAAAAAFk74n+cGzz4x8=" + }, + "model": { + "$ref": "AAAAAAFk74n+b2zyIZQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 404, + "top": 943, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74n+cGzz4x8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74VZ118qqLI=" + }, + "tail": { + "$ref": "AAAAAAFk74WmIV+5ur0=" + }, + "lineStyle": 0, + "points": "390:1008;390:890", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74n+cGz0sRs=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74n+cGz1144=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74n+cGz2QC8=" + } + } + ] + }, + { + "_type": "UMLClassDiagram", + "_id": "AAAAAAFk74scs3UEoZk=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Loader Diagram", + "visible": true, + "defaultDiagram": false, + "ownedViews": [ + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk74t2wXVUNzc=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74t2wXVVboI=", + "_parent": { + "$ref": "AAAAAAFk74t2wXVUNzc=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74t2wXVW/Kc=", + "_parent": { + "$ref": "AAAAAAFk74t2wXVVboI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 21, + "width": 503, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74t2wnVXKxY=", + "_parent": { + "$ref": "AAAAAAFk74t2wXVVboI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 36, + "width": 503, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageLoader", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74t2wnVYs8g=", + "_parent": { + "$ref": "AAAAAAFk74t2wXVVboI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 51, + "width": 503, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74t2wnVZoss=", + "_parent": { + "$ref": "AAAAAAFk74t2wXVVboI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -706, + "top": -264, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 280, + "top": 16, + "width": 513, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74t2wXVW/Kc=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74t2wnVXKxY=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74t2wnVYs8g=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74t2wnVZoss=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74t2wnVaLgs=", + "_parent": { + "$ref": "AAAAAAFk74t2wXVUNzc=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -353, + "top": -132, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74t2wnVbrI8=", + "_parent": { + "$ref": "AAAAAAFk74t2wXVUNzc=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74t2+HV6bpA=", + "_parent": { + "$ref": "AAAAAAFk74t2wnVbrI8=" + }, + "model": { + "$ref": "AAAAAAFky3AzTGhO/lc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 74, + "width": 527, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+canLoad(url): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74t2+HV90tc=", + "_parent": { + "$ref": "AAAAAAFk74t2wnVbrI8=" + }, + "model": { + "$ref": "AAAAAAFky3CxVms3ePA=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 285, + "top": 89, + "width": 527, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+loadImage(url, options, context, progressBlock, completedBlock): SDWebImageOperation", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 280, + "top": 69, + "width": 537, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74t2wnVcGAU=", + "_parent": { + "$ref": "AAAAAAFk74t2wXVUNzc=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -353, + "top": -132, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74t2w3VdrQI=", + "_parent": { + "$ref": "AAAAAAFk74t2wXVUNzc=" + }, + "model": { + "$ref": "AAAAAAFky29m0WRt7Q8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -353, + "top": -132, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 280, + "top": 16, + "width": 537, + "height": 91, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74t2wXVVboI=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74t2wnVaLgs=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74t2wnVbrI8=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74t2wnVcGAU=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74t2w3VdrQI=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk74ugPXWBqa8=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74ugPXWCCXo=", + "_parent": { + "$ref": "AAAAAAFk74ugPXWBqa8=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74ugPXWDnIo=", + "_parent": { + "$ref": "AAAAAAFk74ugPXWCCXo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1292, + "top": -312, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74ugPXWEmO4=", + "_parent": { + "$ref": "AAAAAAFk74ugPXWCCXo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 183, + "width": 202, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDImageLoadersManager", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74ugPXWFH9M=", + "_parent": { + "$ref": "AAAAAAFk74ugPXWCCXo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 198, + "width": 202, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74ugPXWGvpc=", + "_parent": { + "$ref": "AAAAAAFk74ugPXWCCXo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1292, + "top": -312, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 176, + "width": 212, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74ugPXWDnIo=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74ugPXWEmO4=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74ugPXWFH9M=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74ugPXWGvpc=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74ugPXWHIRY=", + "_parent": { + "$ref": "AAAAAAFk74ugPXWBqa8=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74ugonWyIjk=", + "_parent": { + "$ref": "AAAAAAFk74ugPXWHIRY=" + }, + "model": { + "$ref": "AAAAAAFkzOIg/+78rRg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 221, + "width": 202, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedManager", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74ugo3W1QSo=", + "_parent": { + "$ref": "AAAAAAFk74ugPXWHIRY=" + }, + "model": { + "$ref": "AAAAAAFkzOOPjva3FJM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 236, + "width": 202, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+loaders: Array ", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 216, + "width": 212, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74ugPXWI2Ho=", + "_parent": { + "$ref": "AAAAAAFk74ugPXWBqa8=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74ugo3W4CBw=", + "_parent": { + "$ref": "AAAAAAFk74ugPXWI2Ho=" + }, + "model": { + "$ref": "AAAAAAFkzOP6yPhv64w=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 259, + "width": 202, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+addLoader()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74ugpHW7WWc=", + "_parent": { + "$ref": "AAAAAAFk74ugPXWI2Ho=" + }, + "model": { + "$ref": "AAAAAAFkzOQxGfm6yKY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 274, + "width": 202, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+removeLoader()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 254, + "width": 212, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74ugPXWJ5XM=", + "_parent": { + "$ref": "AAAAAAFk74ugPXWBqa8=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -646, + "top": -156, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74ugPnWKEe4=", + "_parent": { + "$ref": "AAAAAAFk74ugPXWBqa8=" + }, + "model": { + "$ref": "AAAAAAFkzOBPBONMct8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -646, + "top": -156, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 16, + "top": 176, + "width": 212, + "height": 116, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74ugPXWCCXo=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74ugPXWHIRY=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74ugPXWI2Ho=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74ugPXWJ5XM=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74ugPnWKEe4=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk74ugPnWLDSg=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFk7AFZvlix+G0=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74ugPnWMGSg=", + "_parent": { + "$ref": "AAAAAAFk74ugPnWLDSg=" + }, + "model": { + "$ref": "AAAAAAFk7AFZvlix+G0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 136, + "top": 59, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74ugPnWLDSg=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74ugP3WNo9M=", + "_parent": { + "$ref": "AAAAAAFk74ugPnWLDSg=" + }, + "model": { + "$ref": "AAAAAAFk7AFZvlix+G0=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 136, + "top": 44, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74ugPnWLDSg=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74ugP3WOnvY=", + "_parent": { + "$ref": "AAAAAAFk74ugPnWLDSg=" + }, + "model": { + "$ref": "AAAAAAFk7AFZvlix+G0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 136, + "top": 89, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74ugPnWLDSg=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74t2wXVUNzc=" + }, + "tail": { + "$ref": "AAAAAAFk74ugPXWBqa8=" + }, + "lineStyle": 0, + "points": "136:176;136:80;280:80", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74ugPnWMGSg=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74ugP3WNo9M=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74ugP3WOnvY=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk74us0XXCIlQ=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74us0XXDZlk=", + "_parent": { + "$ref": "AAAAAAFk74us0XXCIlQ=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74us0XXEgEs=", + "_parent": { + "$ref": "AAAAAAFk74us0XXDZlk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -336, + "top": -310, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74us0XXFhfQ=", + "_parent": { + "$ref": "AAAAAAFk74us0XXDZlk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 183, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloader", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74us0XXGkTk=", + "_parent": { + "$ref": "AAAAAAFk74us0XXDZlk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 198, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74us0nXH+vI=", + "_parent": { + "$ref": "AAAAAAFk74us0XXDZlk=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -336, + "top": -310, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 288, + "top": 176, + "width": 523, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74us0XXEgEs=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74us0XXFhfQ=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74us0XXGkTk=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74us0nXH+vI=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74us0nXIXC8=", + "_parent": { + "$ref": "AAAAAAFk74us0XXCIlQ=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74utN3XzuZA=", + "_parent": { + "$ref": "AAAAAAFk74us0nXIXC8=" + }, + "model": { + "$ref": "AAAAAAFUkiJAhI5kL78=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 221, + "width": 513, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+sharedDownloader", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74utOHX2KdU=", + "_parent": { + "$ref": "AAAAAAFk74us0nXIXC8=" + }, + "model": { + "$ref": "AAAAAAFUmOMr1ewzvaI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 236, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+config: SDWebImageDownloaderConfig", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74utOHX5HBk=", + "_parent": { + "$ref": "AAAAAAFk74us0nXIXC8=" + }, + "model": { + "$ref": "AAAAAAFUmONDtOzuN2c=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 251, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+requestModifier: SDWebImageDownloaderRequestModifier", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74utOHX8xZY=", + "_parent": { + "$ref": "AAAAAAFk74us0nXIXC8=" + }, + "model": { + "$ref": "AAAAAAFUmOaPcvo7CuM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 266, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sessionConfiguration", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74utOXX/7e0=", + "_parent": { + "$ref": "AAAAAAFk74us0nXIXC8=" + }, + "model": { + "$ref": "AAAAAAFUmOa7+/r2ysU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 281, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+suspended", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74utOXYCUuM=", + "_parent": { + "$ref": "AAAAAAFk74us0nXIXC8=" + }, + "model": { + "$ref": "AAAAAAFUmOiCz/5aGv0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 296, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+currentDownloadCount", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 288, + "top": 216, + "width": 523, + "height": 98, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74us0nXJPMc=", + "_parent": { + "$ref": "AAAAAAFk74us0XXCIlQ=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74utOXYFUNI=", + "_parent": { + "$ref": "AAAAAAFk74us0nXJPMc=" + }, + "model": { + "$ref": "AAAAAAFXmuCdynfN50Y=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 319, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(config)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74utOnYIDjM=", + "_parent": { + "$ref": "AAAAAAFk74us0nXJPMc=" + }, + "model": { + "$ref": "AAAAAAFUmOeh6PwLtkk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 334, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+setValue(value, HTTPHeaderField)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74utOnYLHQg=", + "_parent": { + "$ref": "AAAAAAFk74us0nXJPMc=" + }, + "model": { + "$ref": "AAAAAAFky3dFIIXZ21M=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 349, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+value(HTTPHeaderField): String", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74utO3YOKsA=", + "_parent": { + "$ref": "AAAAAAFk74us0nXJPMc=" + }, + "model": { + "$ref": "AAAAAAFUmOOite2pkfo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 364, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+downloadImage(url, options, context, progressBlock, completedBlock): DownloadToken", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74utO3YR29c=", + "_parent": { + "$ref": "AAAAAAFk74us0nXJPMc=" + }, + "model": { + "$ref": "AAAAAAFUmOgcH/2BRjw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 379, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cancelAllDownloads()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74utO3YUxY8=", + "_parent": { + "$ref": "AAAAAAFk74us0nXJPMc=" + }, + "model": { + "$ref": "AAAAAAFUmOZtsvmAcFQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 293, + "top": 394, + "width": 513, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+invalidateSessionAndCancel()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 288, + "top": 314, + "width": 523, + "height": 98, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74us0nXKUhs=", + "_parent": { + "$ref": "AAAAAAFk74us0XXCIlQ=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -168, + "top": -155, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74us0nXLqi0=", + "_parent": { + "$ref": "AAAAAAFk74us0XXCIlQ=" + }, + "model": { + "$ref": "AAAAAAFUkh8UMI38gtY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -168, + "top": -155, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 288, + "top": 176, + "width": 523, + "height": 236, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74us0XXDZlk=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74us0nXIXC8=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74us0nXJPMc=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74us0nXKUhs=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74us0nXLqi0=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk74us0nXMDPE=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFk73Wx7ywf4cU=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74us0nXN7cQ=", + "_parent": { + "$ref": "AAAAAAFk74us0nXMDPE=" + }, + "model": { + "$ref": "AAAAAAFk73Wx7ywf4cU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 533, + "top": 134, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74us0nXMDPE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74us0nXOdt8=", + "_parent": { + "$ref": "AAAAAAFk74us0nXMDPE=" + }, + "model": { + "$ref": "AAAAAAFk73Wx7ywf4cU=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 518, + "top": 134, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74us0nXMDPE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74us0nXPJco=", + "_parent": { + "$ref": "AAAAAAFk74us0nXMDPE=" + }, + "model": { + "$ref": "AAAAAAFk73Wx7ywf4cU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 562, + "top": 135, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74us0nXMDPE=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74t2wXVUNzc=" + }, + "tail": { + "$ref": "AAAAAAFk74us0XXCIlQ=" + }, + "lineStyle": 0, + "points": "548:176;548:106", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74us0nXN7cQ=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74us0nXOdt8=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74us0nXPJco=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk74u4snYbwho=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74u4snYc+QE=", + "_parent": { + "$ref": "AAAAAAFk74u4snYbwho=" + }, + "model": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74u4snYd1n8=", + "_parent": { + "$ref": "AAAAAAFk74u4snYc+QE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -106, + "top": 314, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74u4snYexIw=", + "_parent": { + "$ref": "AAAAAAFk74u4snYc+QE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 271, + "width": 198, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloaderConfig", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74u4snYfiNo=", + "_parent": { + "$ref": "AAAAAAFk74u4snYc+QE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 286, + "width": 198, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74u4snYgh2c=", + "_parent": { + "$ref": "AAAAAAFk74u4snYc+QE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -106, + "top": 314, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 896, + "top": 264, + "width": 208, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74u4snYd1n8=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74u4snYexIw=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74u4snYfiNo=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74u4snYgh2c=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74u4snYhBS8=", + "_parent": { + "$ref": "AAAAAAFk74u4snYbwho=" + }, + "model": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74u5F3ZMZhU=", + "_parent": { + "$ref": "AAAAAAFk74u4snYhBS8=" + }, + "model": { + "$ref": "AAAAAAFky4zOJs9aW9c=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 309, + "width": 198, + "height": 13, + "autoResize": false, + "underline": true, + "text": "+default", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74u5F3ZPANY=", + "_parent": { + "$ref": "AAAAAAFk74u4snYhBS8=" + }, + "model": { + "$ref": "AAAAAAFky4z9vtF/kCc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 324, + "width": 198, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+maxConcurrentDownloads", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74u5GHZSRQI=", + "_parent": { + "$ref": "AAAAAAFk74u4snYhBS8=" + }, + "model": { + "$ref": "AAAAAAFky40X5tLK/zc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 339, + "width": 198, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+downloadTimeout", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74u5GHZV6vI=", + "_parent": { + "$ref": "AAAAAAFk74u4snYhBS8=" + }, + "model": { + "$ref": "AAAAAAFky400JdQVn+Q=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 354, + "width": 198, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+sessionConfiguration", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74u5GHZY4NA=", + "_parent": { + "$ref": "AAAAAAFk74u4snYhBS8=" + }, + "model": { + "$ref": "AAAAAAFky41Rt9Vg34c=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 369, + "width": 198, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+operationClass", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74u5GXZbu1Q=", + "_parent": { + "$ref": "AAAAAAFk74u4snYhBS8=" + }, + "model": { + "$ref": "AAAAAAFky419KNarbXU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 384, + "width": 198, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+executionOrder", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74u5GXZeaz8=", + "_parent": { + "$ref": "AAAAAAFk74u4snYhBS8=" + }, + "model": { + "$ref": "AAAAAAFky42Z0df2Ke8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 399, + "width": 198, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+urlCredential", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74u5GXZhJPk=", + "_parent": { + "$ref": "AAAAAAFk74u4snYhBS8=" + }, + "model": { + "$ref": "AAAAAAFky424lNlB4TI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 414, + "width": 198, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+username", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74u5GnZk6K8=", + "_parent": { + "$ref": "AAAAAAFk74u4snYhBS8=" + }, + "model": { + "$ref": "AAAAAAFky43MudqMI9E=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 429, + "width": 198, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+password", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 896, + "top": 304, + "width": 208, + "height": 143, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74u4snYiJZA=", + "_parent": { + "$ref": "AAAAAAFk74u4snYbwho=" + }, + "model": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 896, + "top": 447, + "width": 208, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74u4snYjLQI=", + "_parent": { + "$ref": "AAAAAAFk74u4snYbwho=" + }, + "model": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -53, + "top": 157, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74u4snYkpjs=", + "_parent": { + "$ref": "AAAAAAFk74u4snYbwho=" + }, + "model": { + "$ref": "AAAAAAFky4wTy8jjfCc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -53, + "top": 157, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 896, + "top": 264, + "width": 208, + "height": 193, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74u4snYc+QE=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74u4snYhBS8=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74u4snYiJZA=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74u4snYjLQI=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74u4snYkpjs=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk74u4s3YlZec=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFXmuZ1booW7c8=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74u4s3Ym2+A=", + "_parent": { + "$ref": "AAAAAAFk74u4s3YlZec=" + }, + "model": { + "$ref": "AAAAAAFXmuZ1booW7c8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 853, + "top": 260, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74u4s3YlZec=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74u4s3YnjEk=", + "_parent": { + "$ref": "AAAAAAFk74u4s3YlZec=" + }, + "model": { + "$ref": "AAAAAAFXmuZ1booW7c8=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 853, + "top": 245, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74u4s3YlZec=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74u4s3Yoo/c=", + "_parent": { + "$ref": "AAAAAAFk74u4s3YlZec=" + }, + "model": { + "$ref": "AAAAAAFXmuZ1booW7c8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 853, + "top": 290, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74u4s3YlZec=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74u4snYbwho=" + }, + "tail": { + "$ref": "AAAAAAFk74us0XXCIlQ=" + }, + "lineStyle": 0, + "points": "810:281;896:281", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74u4s3Ym2+A=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74u4s3YnjEk=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74u4s3Yoo/c=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk74wQ43ZtYf8=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74wQ43ZuDn0=", + "_parent": { + "$ref": "AAAAAAFk74wQ43ZtYf8=" + }, + "model": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74wQ43ZvQ7A=", + "_parent": { + "$ref": "AAAAAAFk74wQ43ZuDn0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -706, + "top": 180, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74wQ43Zwebo=", + "_parent": { + "$ref": "AAAAAAFk74wQ43ZuDn0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 613, + "top": 599, + "width": 258, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloaderRequestModifier", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74wQ43ZxyFk=", + "_parent": { + "$ref": "AAAAAAFk74wQ43ZuDn0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 613, + "top": 614, + "width": 258, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74wQ5HZyuqk=", + "_parent": { + "$ref": "AAAAAAFk74wQ43ZuDn0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -706, + "top": 180, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 608, + "top": 592, + "width": 268, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74wQ43ZvQ7A=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74wQ43Zwebo=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74wQ43ZxyFk=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74wQ5HZyuqk=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74wQ5HZz0OU=", + "_parent": { + "$ref": "AAAAAAFk74wQ43ZtYf8=" + }, + "model": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 608, + "top": 632, + "width": 268, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74wQ5HZ03dA=", + "_parent": { + "$ref": "AAAAAAFk74wQ43ZtYf8=" + }, + "model": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74wQ7HaTyyg=", + "_parent": { + "$ref": "AAAAAAFk74wQ5HZ03dA=" + }, + "model": { + "$ref": "AAAAAAFky5ZuM/uFU/4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 613, + "top": 647, + "width": 258, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(block)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 608, + "top": 642, + "width": 268, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74wQ5HZ19g4=", + "_parent": { + "$ref": "AAAAAAFk74wQ43ZtYf8=" + }, + "model": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -353, + "top": 90, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74wQ5HZ2WyY=", + "_parent": { + "$ref": "AAAAAAFk74wQ43ZtYf8=" + }, + "model": { + "$ref": "AAAAAAFky5XHEfWLtyM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -353, + "top": 90, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 608, + "top": 592, + "width": 268, + "height": 73, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74wQ43ZuDn0=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74wQ5HZz0OU=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74wQ5HZ03dA=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74wQ5HZ19g4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74wQ5HZ2WyY=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk74xR1HaXRr0=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74xR1HaYUWI=", + "_parent": { + "$ref": "AAAAAAFk74xR1HaXRr0=" + }, + "model": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74xR1HaZF9s=", + "_parent": { + "$ref": "AAAAAAFk74xR1HaYUWI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 589, + "top": 469, + "width": 268, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74xR1Haa3aw=", + "_parent": { + "$ref": "AAAAAAFk74xR1HaYUWI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 589, + "top": 484, + "width": 268, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloaderRequestModifier", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74xR1HabuNI=", + "_parent": { + "$ref": "AAAAAAFk74xR1HaYUWI=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 589, + "top": 499, + "width": 268, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74xR1Hacg2A=", + "_parent": { + "$ref": "AAAAAAFk74xR1HaYUWI=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -478, + "top": -232, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 584, + "top": 464, + "width": 278, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74xR1HaZF9s=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74xR1Haa3aw=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74xR1HabuNI=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74xR1Hacg2A=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74xR1Hadmug=", + "_parent": { + "$ref": "AAAAAAFk74xR1HaXRr0=" + }, + "model": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -239, + "top": -116, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74xR1HaeLok=", + "_parent": { + "$ref": "AAAAAAFk74xR1HaXRr0=" + }, + "model": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74xR23a9VRc=", + "_parent": { + "$ref": "AAAAAAFk74xR1HaeLok=" + }, + "model": { + "$ref": "AAAAAAFky5N7SPLYdL0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 589, + "top": 522, + "width": 292, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+modifiedRequest(request): URLRequest", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 584, + "top": 517, + "width": 302, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74xR1HafzBo=", + "_parent": { + "$ref": "AAAAAAFk74xR1HaXRr0=" + }, + "model": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -239, + "top": -116, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74xR1HagmNM=", + "_parent": { + "$ref": "AAAAAAFk74xR1HaXRr0=" + }, + "model": { + "$ref": "AAAAAAFky49vaeVTiPQ=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -239, + "top": -116, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 584, + "top": 464, + "width": 302, + "height": 76, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74xR1HaYUWI=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74xR1Hadmug=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74xR1HaeLok=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74xR1HafzBo=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74xR1HagmNM=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk74xtDXbBBXw=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74xtDXbCvSs=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbBBXw=" + }, + "model": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74xtDXbDm9I=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbCvSs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 629, + "width": 248, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74xtDXbEfVA=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbCvSs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 644, + "width": 248, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloaderOperation", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74xtDXbF1sI=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbCvSs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 659, + "width": 248, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74xtDXbGUHI=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbCvSs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -2752, + "top": 1004, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 624, + "width": 258, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74xtDXbDm9I=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74xtDXbEfVA=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74xtDXbF1sI=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74xtDXbGUHI=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74xtDXbHVRM=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbBBXw=" + }, + "model": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1376, + "top": 502, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74xtDXbIl6E=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbBBXw=" + }, + "model": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74xtFXbn1KM=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbIl6E=" + }, + "model": { + "$ref": "AAAAAAFky4EnyJoHXgk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 682, + "width": 272, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+init(request, session, options, context)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74xtFXbqFPA=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbIl6E=" + }, + "model": { + "$ref": "AAAAAAFky4L4L6FsOVg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 697, + "width": 272, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+addHandlers(progressBlock, completedBlock)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74xtFnbtpYM=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbIl6E=" + }, + "model": { + "$ref": "AAAAAAFky4PT6qQes1w=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 712, + "width": 272, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+credential(): URLCredential", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74xtFnbwW9E=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbIl6E=" + }, + "model": { + "$ref": "AAAAAAFky4QsQ6YrSFU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 727, + "width": 272, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+setCredential(value)", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74xtFnbzqj4=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbIl6E=" + }, + "model": { + "$ref": "AAAAAAFky4SFRKgB5qs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 742, + "width": 272, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cancel(token): Bool", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74xtF3b2+3M=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbIl6E=" + }, + "model": { + "$ref": "AAAAAAFky4UEV6rqaoE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 757, + "width": 272, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+request()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74xtF3b5SeE=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbIl6E=" + }, + "model": { + "$ref": "AAAAAAFky4U4wKw1It0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 772, + "width": 272, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+response()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk74xtF3b8l8g=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbIl6E=" + }, + "model": { + "$ref": "AAAAAAFky4VpKK2AUTU=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 787, + "width": 272, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+dataTask(): URLSessionTask", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 677, + "width": 282, + "height": 128, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74xtDXbJMrk=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbBBXw=" + }, + "model": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1376, + "top": 502, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74xtDXbKsWA=", + "_parent": { + "$ref": "AAAAAAFk74xtDXbBBXw=" + }, + "model": { + "$ref": "AAAAAAFXmwdRJMUYGTs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1376, + "top": 502, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 16, + "top": 624, + "width": 282, + "height": 181, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74xtDXbCvSs=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74xtDXbHVRM=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74xtDXbIl6E=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74xtDXbJMrk=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74xtDXbKsWA=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk74yHFXcA8wc=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk74yHFXcBM7Q=", + "_parent": { + "$ref": "AAAAAAFk74yHFXcA8wc=" + }, + "model": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk74yHFXcCxvc=", + "_parent": { + "$ref": "AAAAAAFk74yHFXcBM7Q=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -2566, + "top": 402, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74yHFXcD8wE=", + "_parent": { + "$ref": "AAAAAAFk74yHFXcBM7Q=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 471, + "width": 183, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloadToken", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74yHFXcEkdo=", + "_parent": { + "$ref": "AAAAAAFk74yHFXcBM7Q=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 486, + "width": 183, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk74yHFXcF/Vs=", + "_parent": { + "$ref": "AAAAAAFk74yHFXcBM7Q=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -2566, + "top": 402, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 312, + "top": 464, + "width": 193, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk74yHFXcCxvc=" + }, + "nameLabel": { + "$ref": "AAAAAAFk74yHFXcD8wE=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk74yHFXcEkdo=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74yHFXcF/Vs=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk74yHFncGZSU=", + "_parent": { + "$ref": "AAAAAAFk74yHFXcA8wc=" + }, + "model": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74yHIXcm0jc=", + "_parent": { + "$ref": "AAAAAAFk74yHFncGZSU=" + }, + "model": { + "$ref": "AAAAAAFXmuY4yIivPbY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 509, + "width": 183, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+url", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74yHIXcpioY=", + "_parent": { + "$ref": "AAAAAAFk74yHFncGZSU=" + }, + "model": { + "$ref": "AAAAAAFXmuZPjolqbRg=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 524, + "width": 183, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+request", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk74yHIncsL1c=", + "_parent": { + "$ref": "AAAAAAFk74yHFncGZSU=" + }, + "model": { + "$ref": "AAAAAAFky24wtWMHKQ0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 539, + "width": 183, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+response", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 312, + "top": 504, + "width": 193, + "height": 53, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk74yHFncH3Kk=", + "_parent": { + "$ref": "AAAAAAFk74yHFXcA8wc=" + }, + "model": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 312, + "top": 557, + "width": 193, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk74yHFncIlzw=", + "_parent": { + "$ref": "AAAAAAFk74yHFXcA8wc=" + }, + "model": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1283, + "top": 201, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk74yHFncJL0I=", + "_parent": { + "$ref": "AAAAAAFk74yHFXcA8wc=" + }, + "model": { + "$ref": "AAAAAAFXmuJtT3q/PXo=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1283, + "top": 201, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 312, + "top": 464, + "width": 193, + "height": 103, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk74yHFXcBM7Q=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk74yHFncGZSU=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk74yHFncH3Kk=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk74yHFncIlzw=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk74yHFncJL0I=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk740LdXc56Mg=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk740LdXc6wGY=", + "_parent": { + "$ref": "AAAAAAFk740LdXc56Mg=" + }, + "model": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk740LdXc7cY0=", + "_parent": { + "$ref": "AAAAAAFk740LdXc6wGY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -3458, + "top": 674, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk740LdXc8VxI=", + "_parent": { + "$ref": "AAAAAAFk740LdXc6wGY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 471, + "width": 250, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloaderOperation", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk740LdXc9G3s=", + "_parent": { + "$ref": "AAAAAAFk740LdXc6wGY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 486, + "width": 250, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk740LdXc+nuI=", + "_parent": { + "$ref": "AAAAAAFk740LdXc6wGY=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -3458, + "top": 674, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 464, + "width": 260, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk740LdXc7cY0=" + }, + "nameLabel": { + "$ref": "AAAAAAFk740LdXc8VxI=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk740LdXc9G3s=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk740LdXc+nuI=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk740LdXc/6Us=", + "_parent": { + "$ref": "AAAAAAFk740LdXc56Mg=" + }, + "model": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk740LfndfO0g=", + "_parent": { + "$ref": "AAAAAAFk740LdXc/6Us=" + }, + "model": { + "$ref": "AAAAAAFUmO2TmQzzs/g=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 509, + "width": 250, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+options: SDWebImageDownloaderOptions", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAFk740Lf3digjw=", + "_parent": { + "$ref": "AAAAAAFk740LdXc/6Us=" + }, + "model": { + "$ref": "AAAAAAFky4mAub8FNII=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 21, + "top": 524, + "width": 250, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+context", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 504, + "width": 260, + "height": 38, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk740LdXdAXrc=", + "_parent": { + "$ref": "AAAAAAFk740LdXc56Mg=" + }, + "model": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 16, + "top": 542, + "width": 260, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk740LdndB5WM=", + "_parent": { + "$ref": "AAAAAAFk740LdXc56Mg=" + }, + "model": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1729, + "top": 337, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk740LdndCees=", + "_parent": { + "$ref": "AAAAAAFk740LdXc56Mg=" + }, + "model": { + "$ref": "AAAAAAFUkiR/Go5pUW0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1729, + "top": 337, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 16, + "top": 464, + "width": 260, + "height": 88, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk740LdXc6wGY=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk740LdXc/6Us=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk740LdXdAXrc=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk740LdndB5WM=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk740LdndCees=" + } + }, + { + "_type": "UMLInterfaceView", + "_id": "AAAAAAFk741MB3dmaOc=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk741MB3dn6h8=", + "_parent": { + "$ref": "AAAAAAFk741MB3dmaOc=" + }, + "model": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk741MCHdoa/4=", + "_parent": { + "$ref": "AAAAAAFk741MB3dn6h8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 629, + "width": 154, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«interface»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk741MCHdpnoU=", + "_parent": { + "$ref": "AAAAAAFk741MB3dn6h8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 644, + "width": 154, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageOperation", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk741MCHdqEYE=", + "_parent": { + "$ref": "AAAAAAFk741MB3dn6h8=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 659, + "width": 154, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk741MCHdrlRQ=", + "_parent": { + "$ref": "AAAAAAFk741MB3dn6h8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -2306, + "top": 364, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 312, + "top": 624, + "width": 164, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk741MCHdoa/4=" + }, + "nameLabel": { + "$ref": "AAAAAAFk741MCHdpnoU=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk741MCHdqEYE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk741MCHdrlRQ=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk741MCHdsDXU=", + "_parent": { + "$ref": "AAAAAAFk741MB3dmaOc=" + }, + "model": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1153, + "top": 182, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk741MCHdtteY=", + "_parent": { + "$ref": "AAAAAAFk741MB3dmaOc=" + }, + "model": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAFk741MEHeMo60=", + "_parent": { + "$ref": "AAAAAAFk741MCHdtteY=" + }, + "model": { + "$ref": "AAAAAAFUmNWHXtbX7L0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 317, + "top": 682, + "width": 178, + "height": 13, + "autoResize": false, + "underline": false, + "text": "+cancel()", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 312, + "top": 677, + "width": 188, + "height": 23, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk741MCHduueY=", + "_parent": { + "$ref": "AAAAAAFk741MB3dmaOc=" + }, + "model": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1153, + "top": 182, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk741MCHdvbN0=", + "_parent": { + "$ref": "AAAAAAFk741MB3dmaOc=" + }, + "model": { + "$ref": "AAAAAAFUmNVIhta461s=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1153, + "top": 182, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 312, + "top": 624, + "width": 188, + "height": 76, + "autoResize": false, + "stereotypeDisplay": "decoration-label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk741MB3dn6h8=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk741MCHdsDXU=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk741MCHdtteY=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk741MCHduueY=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk741MCHdvbN0=" + } + }, + { + "_type": "UMLEnumerationView", + "_id": "AAAAAAFk748lMXiHnKg=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk748lMniIIOE=", + "_parent": { + "$ref": "AAAAAAFk748lMXiHnKg=" + }, + "model": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk748lMniJB+8=", + "_parent": { + "$ref": "AAAAAAFk748lMniIIOE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 21, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "«enumeration»", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk748lMniKU7o=", + "_parent": { + "$ref": "AAAAAAFk748lMniIIOE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 36, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageDownloaderOptions", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk748lMniLUbA=", + "_parent": { + "$ref": "AAAAAAFk748lMniIIOE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 51, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk748lMniM2wg=", + "_parent": { + "$ref": "AAAAAAFk748lMniIIOE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -2434, + "top": -730, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 896, + "top": 16, + "width": 216, + "height": 53, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk748lMniJB+8=" + }, + "nameLabel": { + "$ref": "AAAAAAFk748lMniKU7o=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk748lMniLUbA=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk748lMniM2wg=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk748lM3iNTM4=", + "_parent": { + "$ref": "AAAAAAFk748lMXiHnKg=" + }, + "model": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1217, + "top": -365, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk748lM3iOeSA=", + "_parent": { + "$ref": "AAAAAAFk748lMXiHnKg=" + }, + "model": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1217, + "top": -365, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk748lM3iP2oo=", + "_parent": { + "$ref": "AAAAAAFk748lMXiHnKg=" + }, + "model": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1217, + "top": -365, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk748lM3iQNg8=", + "_parent": { + "$ref": "AAAAAAFk748lMXiHnKg=" + }, + "model": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -1217, + "top": -365, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLEnumerationLiteralCompartmentView", + "_id": "AAAAAAFk748lNHiR4Z4=", + "_parent": { + "$ref": "AAAAAAFk748lMXiHnKg=" + }, + "model": { + "$ref": "AAAAAAFUmOC2fugTUX8=" + }, + "subViews": [ + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk748lTXi8VT4=", + "_parent": { + "$ref": "AAAAAAFk748lNHiR4Z4=" + }, + "model": { + "$ref": "AAAAAAFUmODurehEneQ=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 74, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "lowPriority", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk748lT3i/avs=", + "_parent": { + "$ref": "AAAAAAFk748lNHiR4Z4=" + }, + "model": { + "$ref": "AAAAAAFUmOD23ehlAns=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 89, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "progressiveLoad", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk748lT3jCdJA=", + "_parent": { + "$ref": "AAAAAAFk748lNHiR4Z4=" + }, + "model": { + "$ref": "AAAAAAFUmOD+neiGg3g=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 104, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "useNSURLCache", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk748lUHjFpkw=", + "_parent": { + "$ref": "AAAAAAFk748lNHiR4Z4=" + }, + "model": { + "$ref": "AAAAAAFUmOEGbeinNtM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 119, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "ignoreCachedResponse", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk748lUHjIuyc=", + "_parent": { + "$ref": "AAAAAAFk748lNHiR4Z4=" + }, + "model": { + "$ref": "AAAAAAFUmOENpujIT/I=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 134, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "continueInBackground", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk748lUXjL3Pg=", + "_parent": { + "$ref": "AAAAAAFk748lNHiR4Z4=" + }, + "model": { + "$ref": "AAAAAAFUmOEVzujp/Q0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 149, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "handleCookies", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk748lUnjOXug=", + "_parent": { + "$ref": "AAAAAAFk748lNHiR4Z4=" + }, + "model": { + "$ref": "AAAAAAFUmOEc/ekKMBo=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 164, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "allowInvalidSSLCertificates", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk748lUnjRhxc=", + "_parent": { + "$ref": "AAAAAAFk748lNHiR4Z4=" + }, + "model": { + "$ref": "AAAAAAFUmOEkLekrSQE=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 179, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "highPriority", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk748lU3jUbRM=", + "_parent": { + "$ref": "AAAAAAFk748lNHiR4Z4=" + }, + "model": { + "$ref": "AAAAAAFky2uhM1TIKQ4=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 194, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "scaleDownLargeImages", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk748lU3jXZCY=", + "_parent": { + "$ref": "AAAAAAFk748lNHiR4Z4=" + }, + "model": { + "$ref": "AAAAAAFky2vJY1YTwQk=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 209, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "avoidDecodeImage", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk748lVHjaJG4=", + "_parent": { + "$ref": "AAAAAAFk748lNHiR4Z4=" + }, + "model": { + "$ref": "AAAAAAFky2viY1deXps=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 224, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "decodeFirstFrameOnly", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLEnumerationLiteralView", + "_id": "AAAAAAFk748lVHjdF8A=", + "_parent": { + "$ref": "AAAAAAFk748lNHiR4Z4=" + }, + "model": { + "$ref": "AAAAAAFky2v7z1ipMKY=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 901, + "top": 239, + "width": 206, + "height": 13, + "autoResize": false, + "underline": false, + "text": "preloadAllFrames", + "horizontalAlignment": 0, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 896, + "top": 69, + "width": 216, + "height": 188, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 896, + "top": 16, + "width": 216, + "height": 241, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk748lMniIIOE=" + }, + "wordWrap": false, + "suppressAttributes": true, + "suppressOperations": true, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk748lM3iNTM4=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk748lM3iOeSA=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk748lM3iP2oo=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk748lM3iQNg8=" + }, + "suppressLiterals": false, + "enumerationLiteralCompartment": { + "$ref": "AAAAAAFk748lNHiR4Z4=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk748lNXiSXfA=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk748lNniTZtg=", + "_parent": { + "$ref": "AAAAAAFk748lNXiSXfA=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 848, + "top": 166, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk748lNXiSXfA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk748lNniU+gk=", + "_parent": { + "$ref": "AAAAAAFk748lNXiSXfA=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 843, + "top": 152, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk748lNXiSXfA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk748lNniVWRU=", + "_parent": { + "$ref": "AAAAAAFk748lNXiSXfA=" + }, + "model": { + "$ref": "AAAAAAFfKuwBKAhI5QU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 857, + "top": 195, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk748lNXiSXfA=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk748lMXiHnKg=" + }, + "tail": { + "$ref": "AAAAAAFk74us0XXCIlQ=" + }, + "lineStyle": 1, + "points": "811:202;895:173", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk748lNniTZtg=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk748lNniU+gk=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk748lNniVWRU=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk74+x9Xml+Rs=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFk74+x9HmjbAc=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74+x9XmmIBw=", + "_parent": { + "$ref": "AAAAAAFk74+x9Xml+Rs=" + }, + "model": { + "$ref": "AAAAAAFk74+x9HmjbAc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 856, + "top": 27, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74+x9Xml+Rs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74+x9nmnNBE=", + "_parent": { + "$ref": "AAAAAAFk74+x9Xml+Rs=" + }, + "model": { + "$ref": "AAAAAAFk74+x9HmjbAc=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 856, + "top": 12, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk74+x9Xml+Rs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk74+x9nmoemU=", + "_parent": { + "$ref": "AAAAAAFk74+x9Xml+Rs=" + }, + "model": { + "$ref": "AAAAAAFk74+x9HmjbAc=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 856, + "top": 57, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk74+x9Xml+Rs=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk748lMXiHnKg=" + }, + "tail": { + "$ref": "AAAAAAFk74t2wXVUNzc=" + }, + "lineStyle": 0, + "points": "816:48;896:48", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk74+x9XmmIBw=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk74+x9nmnNBE=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk74+x9nmoemU=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAFk75A6HXm8cbc=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFk75A6HHm4W88=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75A6HXm97kA=", + "_parent": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "model": { + "$ref": "AAAAAAFk75A6HHm4W88=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 705, + "top": 430, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75A6HXm+JfQ=", + "_parent": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "model": { + "$ref": "AAAAAAFk75A6HHm4W88=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 690, + "top": 430, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75A6HXm/T+I=", + "_parent": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "model": { + "$ref": "AAAAAAFk75A6HHm4W88=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 734, + "top": 431, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75A6HXnA/Tc=", + "_parent": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "model": { + "$ref": "AAAAAAFk75A6HHm5coU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 705, + "top": 432, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75A6HXnBSRw=", + "_parent": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "model": { + "$ref": "AAAAAAFk75A6HHm5coU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 691, + "top": 429, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75A6HXnCvjY=", + "_parent": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "model": { + "$ref": "AAAAAAFk75A6HHm5coU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 732, + "top": 436, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "edgePosition": 2, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75A6HnnDINg=", + "_parent": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "model": { + "$ref": "AAAAAAFk75A6HHm6YP4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 705, + "top": 430, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75A6HnnEjuE=", + "_parent": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "model": { + "$ref": "AAAAAAFk75A6HHm6YP4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 691, + "top": 433, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75A6HnnFk2k=", + "_parent": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "model": { + "$ref": "AAAAAAFk75A6HHm6YP4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 732, + "top": 426, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "edgePosition": 0, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk75A6HnnGIZ8=", + "_parent": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "model": { + "$ref": "AAAAAAFk75A6HHm5coU=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAFk75A6HnnH/1k=", + "_parent": { + "$ref": "AAAAAAFk75A6HXm8cbc=" + }, + "model": { + "$ref": "AAAAAAFk75A6HHm6YP4=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 0, + "top": 0, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74us0XXCIlQ=" + }, + "tail": { + "$ref": "AAAAAAFk74xR1HaXRr0=" + }, + "lineStyle": 0, + "points": "720:464;720:411", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk75A6HXm97kA=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk75A6HXm+JfQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk75A6HXm/T+I=" + }, + "showMultiplicity": true, + "showType": true, + "tailRoleNameLabel": { + "$ref": "AAAAAAFk75A6HXnA/Tc=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAFk75A6HXnBSRw=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAFk75A6HXnCvjY=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAFk75A6HnnDINg=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAFk75A6HnnEjuE=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAFk75A6HnnFk2k=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAFk75A6HnnGIZ8=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAFk75A6HnnH/1k=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk75BsT3pUEvw=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFk75BsT3pTLSM=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75BsUHpVIhI=", + "_parent": { + "$ref": "AAAAAAFk75BsT3pUEvw=" + }, + "model": { + "$ref": "AAAAAAFk75BsT3pTLSM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 721, + "top": 558, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk75BsT3pUEvw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75BsUHpW7B0=", + "_parent": { + "$ref": "AAAAAAFk75BsT3pUEvw=" + }, + "model": { + "$ref": "AAAAAAFk75BsT3pTLSM=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 706, + "top": 558, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk75BsT3pUEvw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75BsUHpXi3w=", + "_parent": { + "$ref": "AAAAAAFk75BsT3pUEvw=" + }, + "model": { + "$ref": "AAAAAAFk75BsT3pTLSM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 750, + "top": 559, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk75BsT3pUEvw=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74xR1HaXRr0=" + }, + "tail": { + "$ref": "AAAAAAFk74wQ43ZtYf8=" + }, + "lineStyle": 0, + "points": "736:592;736:539", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk75BsUHpVIhI=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk75BsUHpW7B0=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk75BsUHpXi3w=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk75KzQn7OEQ8=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFk75KzQn7NZvE=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75KzQn7PvGM=", + "_parent": { + "$ref": "AAAAAAFk75KzQn7OEQ8=" + }, + "model": { + "$ref": "AAAAAAFk75KzQn7NZvE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 161, + "top": 580, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk75KzQn7OEQ8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75KzQ37Q20Q=", + "_parent": { + "$ref": "AAAAAAFk75KzQn7OEQ8=" + }, + "model": { + "$ref": "AAAAAAFk75KzQn7NZvE=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 176, + "top": 580, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk75KzQn7OEQ8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75KzQ37RJUo=", + "_parent": { + "$ref": "AAAAAAFk75KzQn7OEQ8=" + }, + "model": { + "$ref": "AAAAAAFk75KzQn7NZvE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 132, + "top": 581, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk75KzQn7OEQ8=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74xtDXbBBXw=" + }, + "tail": { + "$ref": "AAAAAAFk740LdXc56Mg=" + }, + "lineStyle": 0, + "points": "147:551;147:624", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk75KzQn7PvGM=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk75KzQ37Q20Q=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk75KzQ37RJUo=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk75MKYn8TT8A=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFk75MKYn8SsQ8=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75MKYn8UqR4=", + "_parent": { + "$ref": "AAAAAAFk75MKYn8TT8A=" + }, + "model": { + "$ref": "AAAAAAFk75MKYn8SsQ8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 288, + "top": 568, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk75MKYn8TT8A=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75MKYn8VfJo=", + "_parent": { + "$ref": "AAAAAAFk75MKYn8TT8A=" + }, + "model": { + "$ref": "AAAAAAFk75MKYn8SsQ8=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 296, + "top": 555, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk75MKYn8TT8A=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75MKYn8WG4E=", + "_parent": { + "$ref": "AAAAAAFk75MKYn8TT8A=" + }, + "model": { + "$ref": "AAAAAAFk75MKYn8SsQ8=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 273, + "top": 593, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk75MKYn8TT8A=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk741MB3dmaOc=" + }, + "tail": { + "$ref": "AAAAAAFk740LdXc56Mg=" + }, + "lineStyle": 1, + "points": "221:552;341:623", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk75MKYn8UqR4=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk75MKYn8VfJo=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk75MKYn8WG4E=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk75MgOn8/1ow=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFk75MgOn8+VeA=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75MgOn9ANv0=", + "_parent": { + "$ref": "AAAAAAFk75MgOn8/1ow=" + }, + "model": { + "$ref": "AAAAAAFk75MgOn8+VeA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 414, + "top": 588, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk75MgOn8/1ow=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75MgOn9BPK8=", + "_parent": { + "$ref": "AAAAAAFk75MgOn8/1ow=" + }, + "model": { + "$ref": "AAAAAAFk75MgOn8+VeA=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 429, + "top": 588, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk75MgOn8/1ow=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75MgOn9ClqQ=", + "_parent": { + "$ref": "AAAAAAFk75MgOn8/1ow=" + }, + "model": { + "$ref": "AAAAAAFk75MgOn8+VeA=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 385, + "top": 589, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk75MgOn8/1ow=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk741MB3dmaOc=" + }, + "tail": { + "$ref": "AAAAAAFk74yHFXcA8wc=" + }, + "lineStyle": 0, + "points": "400:566;400:624", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk75MgOn9ANv0=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk75MgOn9BPK8=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk75MgOn9ClqQ=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk75NrRH+3BKc=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFk75NrQ3+1ToE=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75NrRH+4PwM=", + "_parent": { + "$ref": "AAAAAAFk75NrRH+3BKc=" + }, + "model": { + "$ref": "AAAAAAFk75NrQ3+1ToE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 283, + "top": 444, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk75NrRH+3BKc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75NrRX+5tm8=", + "_parent": { + "$ref": "AAAAAAFk75NrRH+3BKc=" + }, + "model": { + "$ref": "AAAAAAFk75NrQ3+1ToE=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 290, + "top": 457, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk75NrRH+3BKc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75NrRX+6+qA=", + "_parent": { + "$ref": "AAAAAAFk75NrRH+3BKc=" + }, + "model": { + "$ref": "AAAAAAFk75NrQ3+1ToE=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 268, + "top": 417, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk75NrRH+3BKc=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk740LdXc56Mg=" + }, + "tail": { + "$ref": "AAAAAAFk74us0XXCIlQ=" + }, + "lineStyle": 1, + "points": "324:412;228:463", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk75NrRH+4PwM=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk75NrRX+5tm8=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk75NrRX+6+qA=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAFk75N4ZH/dKbo=", + "_parent": { + "$ref": "AAAAAAFk74scs3UEoZk=" + }, + "model": { + "$ref": "AAAAAAFk75N4Y3/bXkw=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75N4ZH/eqek=", + "_parent": { + "$ref": "AAAAAAFk75N4ZH/dKbo=" + }, + "model": { + "$ref": "AAAAAAFk75N4Y3/bXkw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 487, + "top": 430, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk75N4ZH/dKbo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75N4ZH/fC+s=", + "_parent": { + "$ref": "AAAAAAFk75N4ZH/dKbo=" + }, + "model": { + "$ref": "AAAAAAFk75N4Y3/bXkw=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 502, + "top": 430, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk75N4ZH/dKbo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk75N4ZH/g4Gs=", + "_parent": { + "$ref": "AAAAAAFk75N4ZH/dKbo=" + }, + "model": { + "$ref": "AAAAAAFk75N4Y3/bXkw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 458, + "top": 431, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk75N4ZH/dKbo=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk74yHFXcA8wc=" + }, + "tail": { + "$ref": "AAAAAAFk74us0XXCIlQ=" + }, + "lineStyle": 0, + "points": "473:411;473:464", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk75N4ZH/eqek=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk75N4ZH/fC+s=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk75N4ZH/g4Gs=" + } + } + ] + } + ], + "visibility": "public" + } + ] +} \ No newline at end of file diff --git a/Docs/Diagrams/SDWebImageCacheClassDiagram.png b/Docs/Diagrams/SDWebImageCacheClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..04b94f34317259b7704f5498cc44dedff80f13e8 GIT binary patch literal 195766 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

-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

+RE=NdRj2q)RLP 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 z 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

w;2vRKBN0 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™&LDT|W-(gC#~9S}Ud0w|7D+DhbcQQ+c5 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 CKsH+d literal 0 HcmV?d00001 diff --git a/Docs/Diagrams/SDWebImageClassDiagram.png b/Docs/Diagrams/SDWebImageClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..f6a9e2b7ca61bbc81208b8c0fee4217b989071bf GIT binary patch literal 328031 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

|k$GtV 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 literal 0 HcmV?d00001 diff --git a/Docs/Diagrams/SDWebImageCodersClassDiagram.png b/Docs/Diagrams/SDWebImageCodersClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..166fbdf5dd43df785b78dc6d8184cfcb56e3c155 GIT binary patch literal 113615 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ξ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 D^R_-c literal 0 HcmV?d00001 diff --git a/Docs/Diagrams/SDWebImageHighLevelDiagram.jpeg b/Docs/Diagrams/SDWebImageHighLevelDiagram.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4a45c70aa7b4199c0ac9ba5c9bc7ee04ee23823d GIT binary patch literal 209170 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

f$pKK2=2JmZp)G4gg5eNg$k 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�og#2_po_?gU78cD#N-AMSXlg4>oRz< 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 z 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 literal 0 HcmV?d00001 diff --git a/Docs/Diagrams/SDWebImageSequenceDiagram.png b/Docs/Diagrams/SDWebImageSequenceDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..702f1d1140065d6deb8656969da6e79544bbc3a2 GIT binary patch literal 56292 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

~vEmV=eej5%e;c9Wa*^U+38C6ywu)*0|$d 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 literal 0 HcmV?d00001 diff --git a/Docs/Diagrams/SDWebImageTopLevelClassDiagram.png b/Docs/Diagrams/SDWebImageTopLevelClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..c6650cc7a50bf900617454c35cf1690839d71668 GIT binary patch literal 150993 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", - "horizontalAlignment": 0, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 608, - "top": 904, - "width": 248, - "height": 38, - "autoResize": false - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFfKulRsPzGZjg=", - "_parent": { - "$ref": "AAAAAAFfKulRr/y/5nQ=" - }, - "model": { - "$ref": "AAAAAAFfKukEJfyENXE=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFfKvJLEyjrAlw=", - "_parent": { - "$ref": "AAAAAAFfKulRsPzGZjg=" - }, - "model": { - "$ref": "AAAAAAFfKvJK9yjW40I=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 613, - "top": 947, - "width": 238, - "height": 13, - "autoResize": false, - "underline": false, - "text": "+add(coder)", - "horizontalAlignment": 0, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFfKvPFlzM7d88=", - "_parent": { - "$ref": "AAAAAAFfKulRsPzGZjg=" - }, - "model": { - "$ref": "AAAAAAFfKvPFeTMmARs=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 613, - "top": 962, - "width": 238, - "height": 13, - "autoResize": false, - "underline": false, - "text": "+remove(coder)", - "horizontalAlignment": 0, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 608, - "top": 942, - "width": 248, - "height": 38, - "autoResize": false - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFfKulRsfzHiZ8=", - "_parent": { - "$ref": "AAAAAAFfKulRr/y/5nQ=" - }, - "model": { - "$ref": "AAAAAAFfKukEJfyENXE=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 51, - "top": -374, - "width": 10, - "height": 10, - "autoResize": false - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFfKulRsfzIWr8=", - "_parent": { - "$ref": "AAAAAAFfKulRr/y/5nQ=" - }, - "model": { - "$ref": "AAAAAAFfKukEJfyENXE=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 51, - "top": -374, - "width": 10, - "height": 10, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": true, - "containerExtending": false, - "left": 608, - "top": 864, - "width": 248, - "height": 116, - "autoResize": false, - "stereotypeDisplay": "label", - "showVisibility": true, - "showNamespace": true, - "showProperty": true, - "showType": true, - "nameCompartment": { - "$ref": "AAAAAAFfKulRr/zAn18=" - }, - "wordWrap": false, - "suppressAttributes": false, - "suppressOperations": false, - "suppressReceptions": true, - "showMultiplicity": true, - "showOperationSignature": true, - "attributeCompartment": { - "$ref": "AAAAAAFfKulRsPzF/IA=" - }, - "operationCompartment": { - "$ref": "AAAAAAFfKulRsPzGZjg=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFfKulRsfzHiZ8=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFfKulRsfzIWr8=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFfKumI8P16C6U=", - "_parent": { - "$ref": "AAAAAAFF+qBtyKM79qY=" - }, - "model": { - "$ref": "AAAAAAFfKul3rf0/okM=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFfKumI8P17Zb0=", - "_parent": { - "$ref": "AAAAAAFfKumI8P16C6U=" - }, - "model": { - "$ref": "AAAAAAFfKul3rf0/okM=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFfKumI8P18+tw=", - "_parent": { - "$ref": "AAAAAAFfKumI8P17Zb0=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 330, - "top": -556, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFfKumI8P19Lbk=", - "_parent": { - "$ref": "AAAAAAFfKumI8P17Zb0=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;1", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 661, - "top": 1111, - "width": 172, - "height": 13, - "autoResize": false, - "underline": false, - "text": "SDWebImageImageIOCoder", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFfKumI8P1+6As=", - "_parent": { - "$ref": "AAAAAAFfKumI8P17Zb0=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 661, - "top": 1126, - "width": 172, - "height": 13, - "autoResize": false, - "underline": false, - "text": "(from SDWebImage)", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFfKumI8P1/Beo=", - "_parent": { - "$ref": "AAAAAAFfKumI8P17Zb0=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 330, - "top": -556, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 1, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 656, - "top": 1104, - "width": 182, - "height": 40, - "autoResize": false, - "stereotypeLabel": { - "$ref": "AAAAAAFfKumI8P18+tw=" - }, - "nameLabel": { - "$ref": "AAAAAAFfKumI8P19Lbk=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFfKumI8P1+6As=" - }, - "propertyLabel": { - "$ref": "AAAAAAFfKumI8P1/Beo=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFfKumI8P2AZF0=", - "_parent": { - "$ref": "AAAAAAFfKumI8P16C6U=" - }, - "model": { - "$ref": "AAAAAAFfKul3rf0/okM=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 656, - "top": 1144, - "width": 182, - "height": 10, - "autoResize": false - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFfKumI8P2B0+M=", - "_parent": { - "$ref": "AAAAAAFfKumI8P16C6U=" - }, - "model": { - "$ref": "AAAAAAFfKul3rf0/okM=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 656, - "top": 1154, - "width": 182, - "height": 10, - "autoResize": false - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFfKumI8P2CWf4=", - "_parent": { - "$ref": "AAAAAAFfKumI8P16C6U=" - }, - "model": { - "$ref": "AAAAAAFfKul3rf0/okM=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 165, - "top": -278, - "width": 10, - "height": 10, - "autoResize": false - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFfKumI8P2DxlI=", - "_parent": { - "$ref": "AAAAAAFfKumI8P16C6U=" - }, - "model": { - "$ref": "AAAAAAFfKul3rf0/okM=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 165, - "top": -278, - "width": 10, - "height": 10, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": true, - "containerExtending": false, - "left": 656, - "top": 1104, - "width": 182, - "height": 60, - "autoResize": false, - "stereotypeDisplay": "label", - "showVisibility": true, - "showNamespace": true, - "showProperty": true, - "showType": true, - "nameCompartment": { - "$ref": "AAAAAAFfKumI8P17Zb0=" - }, - "wordWrap": false, - "suppressAttributes": false, - "suppressOperations": false, - "suppressReceptions": true, - "showMultiplicity": true, - "showOperationSignature": true, - "attributeCompartment": { - "$ref": "AAAAAAFfKumI8P2AZF0=" - }, - "operationCompartment": { - "$ref": "AAAAAAFfKumI8P2B0+M=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFfKumI8P2CWf4=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFfKumI8P2DxlI=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFfKumzBf41WYU=", - "_parent": { - "$ref": "AAAAAAFF+qBtyKM79qY=" - }, - "model": { - "$ref": "AAAAAAFfKumijf36cE8=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFfKumzBv42z7s=", - "_parent": { - "$ref": "AAAAAAFfKumzBf41WYU=" - }, - "model": { - "$ref": "AAAAAAFfKumijf36cE8=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFfKumzBv43q9A=", - "_parent": { - "$ref": "AAAAAAFfKumzBv42z7s=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 122, - "top": -870, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFfKumzBv44A7s=", - "_parent": { - "$ref": "AAAAAAFfKumzBv42z7s=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;1", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 813, - "top": 1039, - "width": 142, - "height": 13, - "autoResize": false, - "underline": false, - "text": "SDWebImageGIFCoder", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFfKumzBv45dsM=", - "_parent": { - "$ref": "AAAAAAFfKumzBv42z7s=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 813, - "top": 1054, - "width": 142, - "height": 13, - "autoResize": false, - "underline": false, - "text": "(from SDWebImage)", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFfKumzBv46Fe0=", - "_parent": { - "$ref": "AAAAAAFfKumzBv42z7s=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 122, - "top": -870, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 1, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 808, - "top": 1032, - "width": 152, - "height": 40, - "autoResize": false, - "stereotypeLabel": { - "$ref": "AAAAAAFfKumzBv43q9A=" - }, - "nameLabel": { - "$ref": "AAAAAAFfKumzBv44A7s=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFfKumzBv45dsM=" - }, - "propertyLabel": { - "$ref": "AAAAAAFfKumzBv46Fe0=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFfKumzBv47Kuo=", - "_parent": { - "$ref": "AAAAAAFfKumzBf41WYU=" - }, - "model": { - "$ref": "AAAAAAFfKumijf36cE8=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 808, - "top": 1072, - "width": 152, - "height": 10, - "autoResize": false - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFfKumzB/48Lsc=", - "_parent": { - "$ref": "AAAAAAFfKumzBf41WYU=" - }, - "model": { - "$ref": "AAAAAAFfKumijf36cE8=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 808, - "top": 1082, - "width": 152, - "height": 10, - "autoResize": false - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFfKumzB/499l4=", - "_parent": { - "$ref": "AAAAAAFfKumzBf41WYU=" - }, - "model": { - "$ref": "AAAAAAFfKumijf36cE8=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 61, - "top": -435, - "width": 10, - "height": 10, - "autoResize": false - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFfKumzB/4+eKg=", - "_parent": { - "$ref": "AAAAAAFfKumzBf41WYU=" - }, - "model": { - "$ref": "AAAAAAFfKumijf36cE8=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 61, - "top": -435, - "width": 10, - "height": 10, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": true, - "containerExtending": false, - "left": 808, - "top": 1032, - "width": 152, - "height": 60, - "autoResize": false, - "stereotypeDisplay": "label", - "showVisibility": true, - "showNamespace": true, - "showProperty": true, - "showType": true, - "nameCompartment": { - "$ref": "AAAAAAFfKumzBv42z7s=" - }, - "wordWrap": false, - "suppressAttributes": false, - "suppressOperations": false, - "suppressReceptions": true, - "showMultiplicity": true, - "showOperationSignature": true, - "attributeCompartment": { - "$ref": "AAAAAAFfKumzBv47Kuo=" - }, - "operationCompartment": { - "$ref": "AAAAAAFfKumzB/48Lsc=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFfKumzB/499l4=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFfKumzB/4+eKg=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFfKunfeP7w4nM=", - "_parent": { - "$ref": "AAAAAAFF+qBtyKM79qY=" - }, - "model": { - "$ref": "AAAAAAFfKunO1f612hU=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFfKunfeP7xxxs=", - "_parent": { - "$ref": "AAAAAAFfKunfeP7w4nM=" - }, - "model": { - "$ref": "AAAAAAFfKunO1f612hU=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFfKunfeP7yLV4=", - "_parent": { - "$ref": "AAAAAAFfKunfeP7xxxs=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -1002, - "top": -596, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFfKunfeP7zeiI=", - "_parent": { - "$ref": "AAAAAAFfKunfeP7xxxs=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;1", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 517, - "top": 1183, - "width": 156, - "height": 13, - "autoResize": false, - "underline": false, - "text": "SDWebImageWebPCoder", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFfKunfeP70wYg=", - "_parent": { - "$ref": "AAAAAAFfKunfeP7xxxs=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 517, - "top": 1198, - "width": 156, - "height": 13, - "autoResize": false, - "underline": false, - "text": "(from SDWebImage)", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFfKunfeP71LpU=", - "_parent": { - "$ref": "AAAAAAFfKunfeP7xxxs=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -1002, - "top": -596, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 1, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 512, - "top": 1176, - "width": 166, - "height": 40, - "autoResize": false, - "stereotypeLabel": { - "$ref": "AAAAAAFfKunfeP7yLV4=" - }, - "nameLabel": { - "$ref": "AAAAAAFfKunfeP7zeiI=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFfKunfeP70wYg=" - }, - "propertyLabel": { - "$ref": "AAAAAAFfKunfeP71LpU=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFfKunfeP72L2s=", - "_parent": { - "$ref": "AAAAAAFfKunfeP7w4nM=" - }, - "model": { - "$ref": "AAAAAAFfKunO1f612hU=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 512, - "top": 1216, - "width": 166, - "height": 10, - "autoResize": false - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFfKunfeP73sYg=", - "_parent": { - "$ref": "AAAAAAFfKunfeP7w4nM=" - }, - "model": { - "$ref": "AAAAAAFfKunO1f612hU=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 512, - "top": 1226, - "width": 166, - "height": 10, - "autoResize": false - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFfKunfeP74CcA=", - "_parent": { - "$ref": "AAAAAAFfKunfeP7w4nM=" - }, - "model": { - "$ref": "AAAAAAFfKunO1f612hU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -501, - "top": -298, - "width": 10, - "height": 10, - "autoResize": false - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFfKunfeP75I0A=", - "_parent": { - "$ref": "AAAAAAFfKunfeP7w4nM=" - }, - "model": { - "$ref": "AAAAAAFfKunO1f612hU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -501, - "top": -298, - "width": 10, - "height": 10, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": true, - "containerExtending": false, - "left": 512, - "top": 1176, - "width": 166, - "height": 60, - "autoResize": false, - "stereotypeDisplay": "label", - "showVisibility": true, - "showNamespace": true, - "showProperty": true, - "showType": true, - "nameCompartment": { - "$ref": "AAAAAAFfKunfeP7xxxs=" - }, - "wordWrap": false, - "suppressAttributes": false, - "suppressOperations": false, - "suppressReceptions": true, - "showMultiplicity": true, - "showOperationSignature": true, - "attributeCompartment": { - "$ref": "AAAAAAFfKunfeP72L2s=" - }, - "operationCompartment": { - "$ref": "AAAAAAFfKunfeP73sYg=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFfKunfeP74CcA=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFfKunfeP75I0A=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFfKutJugVTfl4=", - "_parent": { - "$ref": "AAAAAAFF+qBtyKM79qY=" - }, - "model": { - "$ref": "AAAAAAFfKutJugVRytg=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKutJuwVU9rw=", - "_parent": { - "$ref": "AAAAAAFfKutJugVTfl4=" - }, - "model": { - "$ref": "AAAAAAFfKutJugVRytg=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 1177, - "top": 1052, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKutJugVTfl4=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKutJuwVVxHc=", - "_parent": { - "$ref": "AAAAAAFfKutJugVTfl4=" - }, - "model": { - "$ref": "AAAAAAFfKutJugVRytg=" - }, - "visible": null, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 1162, - "top": 1052, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKutJugVTfl4=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKutJuwVWtuI=", - "_parent": { - "$ref": "AAAAAAFfKutJugVTfl4=" - }, - "model": { - "$ref": "AAAAAAFfKutJugVRytg=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 1206, - "top": 1053, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKutJugVTfl4=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFfKtnKU+Dd+kU=" - }, - "tail": { - "$ref": "AAAAAAFfKucZUPTSZzA=" - }, - "lineStyle": 0, - "points": "1192:1120;1192:999", - "stereotypeDisplay": "label", - "showVisibility": true, - "showProperty": true, - "nameLabel": { - "$ref": "AAAAAAFfKutJuwVU9rw=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFfKutJuwVVxHc=" - }, - "propertyLabel": { - "$ref": "AAAAAAFfKutJuwVWtuI=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFfKuwBKQhKobU=", - "_parent": { - "$ref": "AAAAAAFF+qBtyKM79qY=" - }, - "model": { - "$ref": "AAAAAAFfKuwBKAhI5QU=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKuwBKghLk+8=", - "_parent": { - "$ref": "AAAAAAFfKuwBKQhKobU=" - }, - "model": { - "$ref": "AAAAAAFfKuwBKAhI5QU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 554, - "top": 859, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKuwBKQhKobU=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKuwBKghMg6U=", - "_parent": { - "$ref": "AAAAAAFfKuwBKQhKobU=" - }, - "model": { - "$ref": "AAAAAAFfKuwBKAhI5QU=" - }, - "visible": null, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 554, - "top": 844, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKuwBKQhKobU=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKuwBKghNzcQ=", - "_parent": { - "$ref": "AAAAAAFfKuwBKQhKobU=" - }, - "model": { - "$ref": "AAAAAAFfKuwBKAhI5QU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 554, - "top": 889, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKuwBKQhKobU=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFfKulRr/y/5nQ=" - }, - "tail": { - "$ref": "AAAAAAFUmNdXmNnpp1I=" - }, - "lineStyle": 0, - "points": "554:840;554:880;608:880", - "stereotypeDisplay": "label", - "showVisibility": true, - "showProperty": true, - "nameLabel": { - "$ref": "AAAAAAFfKuwBKghLk+8=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFfKuwBKghMg6U=" - }, - "propertyLabel": { - "$ref": "AAAAAAFfKuwBKghNzcQ=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFfKuxM+QnrKEs=", - "_parent": { - "$ref": "AAAAAAFF+qBtyKM79qY=" - }, - "model": { - "$ref": "AAAAAAFfKuxM+AnptLY=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKuxM+QnsE1g=", - "_parent": { - "$ref": "AAAAAAFfKuxM+QnrKEs=" - }, - "model": { - "$ref": "AAAAAAFfKuxM+AnptLY=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 955, - "top": 889, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKuxM+QnrKEs=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKuxM+Qntx5Q=", - "_parent": { - "$ref": "AAAAAAFfKuxM+QnrKEs=" - }, - "model": { - "$ref": "AAAAAAFfKuxM+AnptLY=" - }, - "visible": null, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 955, - "top": 904, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKuxM+QnrKEs=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKuxM+QnusHg=", - "_parent": { - "$ref": "AAAAAAFfKuxM+QnrKEs=" - }, - "model": { - "$ref": "AAAAAAFfKuxM+AnptLY=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 956, - "top": 859, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKuxM+QnrKEs=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFfKulRr/y/5nQ=" - }, - "tail": { - "$ref": "AAAAAAFUmNdyjto3Jy4=" - }, - "lineStyle": 0, - "points": "956:810;956:880;855:880", - "stereotypeDisplay": "label", - "showVisibility": true, - "showProperty": true, - "nameLabel": { - "$ref": "AAAAAAFfKuxM+QnsE1g=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFfKuxM+Qntx5Q=" - }, - "propertyLabel": { - "$ref": "AAAAAAFfKuxM+QnusHg=" - } - }, - { - "_type": "UMLInterfaceRealizationView", - "_id": "AAAAAAFfKu3J8hGYD10=", - "_parent": { - "$ref": "AAAAAAFF+qBtyKM79qY=" - }, - "model": { - "$ref": "AAAAAAFfKu3J8hGXH0g=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKu3J8hGZpfY=", - "_parent": { - "$ref": "AAAAAAFfKu3J8hGYD10=" - }, - "model": { - "$ref": "AAAAAAFfKu3J8hGXH0g=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 935, - "top": 883, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKu3J8hGYD10=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKu3J8xGaIH4=", - "_parent": { - "$ref": "AAAAAAFfKu3J8hGYD10=" - }, - "model": { - "$ref": "AAAAAAFfKu3J8hGXH0g=" - }, - "visible": null, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 935, - "top": 868, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKu3J8hGYD10=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKu3J8xGbcAQ=", - "_parent": { - "$ref": "AAAAAAFfKu3J8hGYD10=" - }, - "model": { - "$ref": "AAAAAAFfKu3J8hGXH0g=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 935, - "top": 913, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKu3J8hGYD10=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFfKtnKU+Dd+kU=" - }, - "tail": { - "$ref": "AAAAAAFfKulRr/y/5nQ=" - }, - "lineStyle": 0, - "points": "855:904;1016:904", - "stereotypeDisplay": "label", - "showVisibility": true, - "showProperty": true, - "nameLabel": { - "$ref": "AAAAAAFfKu3J8hGZpfY=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFfKu3J8xGaIH4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFfKu3J8xGbcAQ=" - } - }, - { - "_type": "UMLInterfaceRealizationView", - "_id": "AAAAAAFfKu8vthgM5EM=", - "_parent": { - "$ref": "AAAAAAFF+qBtyKM79qY=" - }, - "model": { - "$ref": "AAAAAAFfKu8vtRgLlUU=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKu8vthgNPAE=", - "_parent": { - "$ref": "AAAAAAFfKu8vthgM5EM=" - }, - "model": { - "$ref": "AAAAAAFfKu8vtRgLlUU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 883, - "top": 910, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKu8vthgM5EM=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKu8vthgOQwY=", - "_parent": { - "$ref": "AAAAAAFfKu8vthgM5EM=" - }, - "model": { - "$ref": "AAAAAAFfKu8vtRgLlUU=" - }, - "visible": null, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 883, - "top": 895, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKu8vthgM5EM=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKu8vtxgPIAE=", - "_parent": { - "$ref": "AAAAAAFfKu8vthgM5EM=" - }, - "model": { - "$ref": "AAAAAAFfKu8vtRgLlUU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 883, - "top": 940, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKu8vthgM5EM=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFfKtnKU+Dd+kU=" - }, - "tail": { - "$ref": "AAAAAAFfKumzBf41WYU=" - }, - "lineStyle": 0, - "points": "883:1032;883:931;1016:931", - "stereotypeDisplay": "label", - "showVisibility": true, - "showProperty": true, - "nameLabel": { - "$ref": "AAAAAAFfKu8vthgNPAE=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFfKu8vthgOQwY=" - }, - "propertyLabel": { - "$ref": "AAAAAAFfKu8vtxgPIAE=" - } - }, - { - "_type": "UMLInterfaceRealizationView", - "_id": "AAAAAAFfKu+znBqrl+4=", - "_parent": { - "$ref": "AAAAAAFF+qBtyKM79qY=" - }, - "model": { - "$ref": "AAAAAAFfKu+znBqqvWQ=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKu+znRqsx/w=", - "_parent": { - "$ref": "AAAAAAFfKu+znBqrl+4=" - }, - "model": { - "$ref": "AAAAAAFfKu+znBqqvWQ=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 934, - "top": 1115, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKu+znBqrl+4=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKu+znRqt1Ng=", - "_parent": { - "$ref": "AAAAAAFfKu+znBqrl+4=" - }, - "model": { - "$ref": "AAAAAAFfKu+znBqqvWQ=" - }, - "visible": null, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 934, - "top": 1100, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKu+znBqrl+4=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKu+znRquxZo=", - "_parent": { - "$ref": "AAAAAAFfKu+znBqrl+4=" - }, - "model": { - "$ref": "AAAAAAFfKu+znBqqvWQ=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 934, - "top": 1145, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKu+znBqrl+4=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFfKucZUPTSZzA=" - }, - "tail": { - "$ref": "AAAAAAFfKumI8P16C6U=" - }, - "lineStyle": 0, - "points": "837:1136;1032:1136", - "stereotypeDisplay": "label", - "showVisibility": true, - "showProperty": true, - "nameLabel": { - "$ref": "AAAAAAFfKu+znRqsx/w=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFfKu+znRqt1Ng=" - }, - "propertyLabel": { - "$ref": "AAAAAAFfKu+znRquxZo=" - } - }, - { - "_type": "UMLInterfaceRealizationView", - "_id": "AAAAAAFfKu/8NRxM/WA=", - "_parent": { - "$ref": "AAAAAAFF+qBtyKM79qY=" - }, - "model": { - "$ref": "AAAAAAFfKu/8NRxLVBY=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKu/8NRxNuNE=", - "_parent": { - "$ref": "AAAAAAFfKu/8NRxM/WA=" - }, - "model": { - "$ref": "AAAAAAFfKu/8NRxLVBY=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 854, - "top": 1171, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKu/8NRxM/WA=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKu/8NRxORNY=", - "_parent": { - "$ref": "AAAAAAFfKu/8NRxM/WA=" - }, - "model": { - "$ref": "AAAAAAFfKu/8NRxLVBY=" - }, - "visible": null, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 854, - "top": 1156, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKu/8NRxM/WA=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKu/8NhxPop4=", - "_parent": { - "$ref": "AAAAAAFfKu/8NRxM/WA=" - }, - "model": { - "$ref": "AAAAAAFfKu/8NRxLVBY=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 854, - "top": 1201, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKu/8NRxM/WA=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFfKucZUPTSZzA=" - }, - "tail": { - "$ref": "AAAAAAFfKunfeP7w4nM=" - }, - "lineStyle": 0, - "points": "677:1192;1032:1192", - "stereotypeDisplay": "label", - "showVisibility": true, - "showProperty": true, - "nameLabel": { - "$ref": "AAAAAAFfKu/8NRxNuNE=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFfKu/8NRxORNY=" - }, - "propertyLabel": { - "$ref": "AAAAAAFfKu/8NhxPop4=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFfKvC15x9YsT0=", - "_parent": { - "$ref": "AAAAAAFF+qBtyKM79qY=" - }, - "model": { - "$ref": "AAAAAAFfKvC15R9UsRU=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvC15x9ZPO4=", - "_parent": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "model": { - "$ref": "AAAAAAFfKvC15R9UsRU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 705, - "top": 1034, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvC15x9aSZk=", - "_parent": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "model": { - "$ref": "AAAAAAFfKvC15R9UsRU=" - }, - "visible": null, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 690, - "top": 1034, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvC15x9bYvY=", - "_parent": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "model": { - "$ref": "AAAAAAFfKvC15R9UsRU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 734, - "top": 1035, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvC15x9czbs=", - "_parent": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9VJ8U=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 705, - "top": 1072, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "edgePosition": 2, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvC15x9d7HI=", - "_parent": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9VJ8U=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 691, - "top": 1069, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "edgePosition": 2, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvC15x9ebo4=", - "_parent": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9VJ8U=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 732, - "top": 1076, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "edgePosition": 2, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvC16B9fh7s=", - "_parent": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9W5gU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 705, - "top": 998, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "edgePosition": 0, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvC16B9gaa4=", - "_parent": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9W5gU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 691, - "top": 1001, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "edgePosition": 0, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvC16B9hcsY=", - "_parent": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9W5gU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 732, - "top": 994, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "edgePosition": 0, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFfKvC16B9ihH0=", - "_parent": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9VJ8U=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 0, - "top": 0, - "width": 10, - "height": 10, - "autoResize": false - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFfKvC16B9j/l0=", - "_parent": { - "$ref": "AAAAAAFfKvC15x9YsT0=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9W5gU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 0, - "top": 0, - "width": 10, - "height": 10, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFfKulRr/y/5nQ=" - }, - "tail": { - "$ref": "AAAAAAFfKumI8P16C6U=" - }, - "lineStyle": 0, - "points": "720:1104;720:979", - "stereotypeDisplay": "label", - "showVisibility": true, - "showProperty": true, - "nameLabel": { - "$ref": "AAAAAAFfKvC15x9ZPO4=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFfKvC15x9aSZk=" - }, - "propertyLabel": { - "$ref": "AAAAAAFfKvC15x9bYvY=" - }, - "showMultiplicity": true, - "showType": true, - "tailRoleNameLabel": { - "$ref": "AAAAAAFfKvC15x9czbs=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFfKvC15x9d7HI=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFfKvC15x9ebo4=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFfKvC16B9fh7s=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFfKvC16B9gaa4=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFfKvC16B9hcsY=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFfKvC16B9ihH0=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFfKvC16B9j/l0=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFfKvEwaulmiZs=", - "_parent": { - "$ref": "AAAAAAFF+qBtyKM79qY=" - }, - "model": { - "$ref": "AAAAAAFfKvC15R9UsRU=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvEwa+lnTns=", - "_parent": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "model": { - "$ref": "AAAAAAFfKvC15R9UsRU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 609, - "top": 1070, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvEwa+lo//k=", - "_parent": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "model": { - "$ref": "AAAAAAFfKvC15R9UsRU=" - }, - "visible": null, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 594, - "top": 1070, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvEwa+lpIjo=", - "_parent": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "model": { - "$ref": "AAAAAAFfKvC15R9UsRU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 639, - "top": 1071, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvEwa+lqVVk=", - "_parent": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9VJ8U=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 609, - "top": 1144, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "edgePosition": 2, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvEwa+lrD0Q=", - "_parent": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9VJ8U=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 595, - "top": 1141, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "edgePosition": 2, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvEwa+lsvJA=", - "_parent": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9VJ8U=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 636, - "top": 1148, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "edgePosition": 2, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvEwa+ltZtE=", - "_parent": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9W5gU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 609, - "top": 998, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "edgePosition": 0, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvEwa+luIMQ=", - "_parent": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9W5gU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 595, - "top": 1001, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "edgePosition": 0, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvEwa+lv4u8=", - "_parent": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9W5gU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 636, - "top": 994, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "edgePosition": 0, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFfKvEwa+lwTrE=", - "_parent": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9VJ8U=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 351, - "top": -193, - "width": 10, - "height": 10, - "autoResize": false - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFfKvEwa+lxJ1c=", - "_parent": { - "$ref": "AAAAAAFfKvEwaulmiZs=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9W5gU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 351, - "top": -193, - "width": 10, - "height": 10, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFfKulRr/y/5nQ=" - }, - "tail": { - "$ref": "AAAAAAFfKunfeP7w4nM=" - }, - "lineStyle": 0, - "points": "624:1176;624:979", - "stereotypeDisplay": "label", - "showVisibility": true, - "showProperty": true, - "nameLabel": { - "$ref": "AAAAAAFfKvEwa+lnTns=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFfKvEwa+lo//k=" - }, - "propertyLabel": { - "$ref": "AAAAAAFfKvEwa+lpIjo=" - }, - "showMultiplicity": true, - "showType": true, - "tailRoleNameLabel": { - "$ref": "AAAAAAFfKvEwa+lqVVk=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFfKvEwa+lrD0Q=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFfKvEwa+lsvJA=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFfKvEwa+ltZtE=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFfKvEwa+luIMQ=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFfKvEwa+lv4u8=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFfKvEwa+lwTrE=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFfKvEwa+lxJ1c=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFfKvFdGelyJLQ=", - "_parent": { - "$ref": "AAAAAAFF+qBtyKM79qY=" - }, - "model": { - "$ref": "AAAAAAFfKvC15R9UsRU=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvFdGelz4Bc=", - "_parent": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "model": { - "$ref": "AAAAAAFfKvC15R9UsRU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 825, - "top": 998, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvFdGel0U/I=", - "_parent": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "model": { - "$ref": "AAAAAAFfKvC15R9UsRU=" - }, - "visible": null, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 810, - "top": 998, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvFdGel1Ky0=", - "_parent": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "model": { - "$ref": "AAAAAAFfKvC15R9UsRU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 854, - "top": 999, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvFdGel27nU=", - "_parent": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9VJ8U=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 825, - "top": 1000, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "edgePosition": 2, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvFdGul32V4=", - "_parent": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9VJ8U=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 811, - "top": 997, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "edgePosition": 2, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvFdGul4sRo=", - "_parent": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9VJ8U=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 852, - "top": 1004, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "edgePosition": 2, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvFdGul5jXU=", - "_parent": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9W5gU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 825, - "top": 998, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "edgePosition": 0, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvFdGul6PbY=", - "_parent": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9W5gU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 811, - "top": 1001, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "edgePosition": 0, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFfKvFdGul7A2c=", - "_parent": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9W5gU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 852, - "top": 994, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "edgePosition": 0, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFfKvFdGul87Dw=", - "_parent": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9VJ8U=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 351, - "top": -193, - "width": 10, - "height": 10, - "autoResize": false - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFfKvFdGul9J64=", - "_parent": { - "$ref": "AAAAAAFfKvFdGelyJLQ=" - }, - "model": { - "$ref": "AAAAAAFfKvC15h9W5gU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 351, - "top": -193, - "width": 10, - "height": 10, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFfKulRr/y/5nQ=" - }, - "tail": { - "$ref": "AAAAAAFfKumzBf41WYU=" - }, - "lineStyle": 0, - "points": "840:1032;840:979", - "stereotypeDisplay": "label", - "showVisibility": true, - "showProperty": true, - "nameLabel": { - "$ref": "AAAAAAFfKvFdGelz4Bc=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFfKvFdGel0U/I=" - }, - "propertyLabel": { - "$ref": "AAAAAAFfKvFdGel1Ky0=" - }, - "showMultiplicity": true, - "showType": true, - "tailRoleNameLabel": { - "$ref": "AAAAAAFfKvFdGel27nU=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFfKvFdGul32V4=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFfKvFdGul4sRo=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFfKvFdGul5jXU=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFfKvFdGul6PbY=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFfKvFdGul7A2c=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFfKvFdGul87Dw=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFfKvFdGul9J64=" - } - } - ] - }, - { - "_type": "UMLCollaboration", - "_id": "AAAAAAFUkhaWOozRCy8=", - "_parent": { - "$ref": "AAAAAAFF+qBWK6M3Z8Y=" - }, - "name": "Collaboration1", - "ownedElements": [ - { - "_type": "UMLInteraction", - "_id": "AAAAAAFUkhaWOozSZjs=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozRCy8=" - }, - "name": "Interaction1", - "ownedElements": [ - { - "_type": "UMLSequenceDiagram", - "_id": "AAAAAAFUkhaWOozTHHk=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "SequenceDiagram1", - "visible": true, - "defaultDiagram": false, - "ownedViews": [ - { - "_type": "UMLSeqLifelineView", - "_id": "AAAAAAFUv2aES8ybhJ8=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFUv2aES8yaBvg=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFUv2aES8ycWzA=", - "_parent": { - "$ref": "AAAAAAFUv2aES8ybhJ8=" - }, - "model": { - "$ref": "AAAAAAFUv2aES8yaBvg=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFUv2aETMydAio=", - "_parent": { - "$ref": "AAAAAAFUv2aES8ycWzA=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -400, - "top": 0, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv2aETMyekVc=", - "_parent": { - "$ref": "AAAAAAFUv2aES8ycWzA=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;1", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 21, - "top": 47, - "width": 93.33544921875, - "height": 13, - "autoResize": false, - "underline": false, - "text": "Other object", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv2aETcyfM5E=", - "_parent": { - "$ref": "AAAAAAFUv2aES8ycWzA=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -400, - "top": 0, - "width": 116.3779296875, - "height": 13, - "autoResize": false, - "underline": false, - "text": "(from Interaction1)", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv2aETcyg6Xc=", - "_parent": { - "$ref": "AAAAAAFUv2aES8ycWzA=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -400, - "top": 0, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 1, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 16, - "top": 40, - "width": 103.33544921875, - "height": 40, - "autoResize": false, - "stereotypeLabel": { - "$ref": "AAAAAAFUv2aETMydAio=" - }, - "nameLabel": { - "$ref": "AAAAAAFUv2aETMyekVc=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFUv2aETcyfM5E=" - }, - "propertyLabel": { - "$ref": "AAAAAAFUv2aETcyg6Xc=" - } - }, - { - "_type": "UMLLinePartView", - "_id": "AAAAAAFUv2aETcyhhXc=", - "_parent": { - "$ref": "AAAAAAFUv2aES8ybhJ8=" - }, - "model": { - "$ref": "AAAAAAFUv2aES8yaBvg=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 68, - "top": 80, - "width": 1, - "height": 399, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 16, - "top": 40, - "width": 103.33544921875, - "height": 439, - "autoResize": false, - "stereotypeDisplay": "label", - "showVisibility": true, - "showNamespace": false, - "showProperty": true, - "showType": true, - "nameCompartment": { - "$ref": "AAAAAAFUv2aES8ycWzA=" - }, - "wordWrap": false, - "linePart": { - "$ref": "AAAAAAFUv2aETcyhhXc=" - } - }, - { - "_type": "UMLSeqLifelineView", - "_id": "AAAAAAFUv2nXaM1BaOI=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFUv2nXaM1AL0k=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFUv2nXaM1CeNE=", - "_parent": { - "$ref": "AAAAAAFUv2nXaM1BaOI=" - }, - "model": { - "$ref": "AAAAAAFUv2nXaM1AL0k=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFUv2nXbM1D228=", - "_parent": { - "$ref": "AAAAAAFUv2nXaM1CeNE=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -1554, - "top": 0, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv2nXbM1ED74=", - "_parent": { - "$ref": "AAAAAAFUv2nXaM1CeNE=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;1", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 133, - "top": 47, - "width": 245.41064453125, - "height": 13, - "autoResize": false, - "underline": false, - "text": "Lifeline1: UIImageView (WebCache)", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv2nXbM1F5i0=", - "_parent": { - "$ref": "AAAAAAFUv2nXaM1CeNE=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -1554, - "top": 0, - "width": 116.3779296875, - "height": 13, - "autoResize": false, - "underline": false, - "text": "(from Interaction1)", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv2nXbM1GtnA=", - "_parent": { - "$ref": "AAAAAAFUv2nXaM1CeNE=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -1554, - "top": 0, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 1, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 128, - "top": 40, - "width": 255.41064453125, - "height": 40, - "autoResize": false, - "stereotypeLabel": { - "$ref": "AAAAAAFUv2nXbM1D228=" - }, - "nameLabel": { - "$ref": "AAAAAAFUv2nXbM1ED74=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFUv2nXbM1F5i0=" - }, - "propertyLabel": { - "$ref": "AAAAAAFUv2nXbM1GtnA=" - } - }, - { - "_type": "UMLLinePartView", - "_id": "AAAAAAFUv2nXbM1HcJ0=", - "_parent": { - "$ref": "AAAAAAFUv2nXaM1BaOI=" - }, - "model": { - "$ref": "AAAAAAFUv2nXaM1AL0k=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 256, - "top": 80, - "width": 1, - "height": 399, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 128, - "top": 40, - "width": 255.41064453125, - "height": 439, - "autoResize": false, - "stereotypeDisplay": "label", - "showVisibility": true, - "showNamespace": false, - "showProperty": true, - "showType": true, - "nameCompartment": { - "$ref": "AAAAAAFUv2nXaM1CeNE=" - }, - "wordWrap": false, - "linePart": { - "$ref": "AAAAAAFUv2nXbM1HcJ0=" - } - }, - { - "_type": "UMLSeqLifelineView", - "_id": "AAAAAAFUv2n3Rc1gg3I=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFUv2n3Rc1fbGI=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFUv2n3Rs1himo=", - "_parent": { - "$ref": "AAAAAAFUv2n3Rc1gg3I=" - }, - "model": { - "$ref": "AAAAAAFUv2n3Rc1fbGI=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFUv2n3Rs1i/NA=", - "_parent": { - "$ref": "AAAAAAFUv2n3Rs1himo=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -1216, - "top": 0, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv2n3Rs1joWc=", - "_parent": { - "$ref": "AAAAAAFUv2n3Rs1himo=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;1", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 605, - "top": 47, - "width": 219.958984375, - "height": 13, - "autoResize": false, - "underline": false, - "text": "Lifeline3: SDWebImageManager", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv2n3Rs1k/4Q=", - "_parent": { - "$ref": "AAAAAAFUv2n3Rs1himo=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -1216, - "top": 0, - "width": 116.3779296875, - "height": 13, - "autoResize": false, - "underline": false, - "text": "(from Interaction1)", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv2n3Rs1lmgQ=", - "_parent": { - "$ref": "AAAAAAFUv2n3Rs1himo=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -1216, - "top": 0, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 1, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 600, - "top": 40, - "width": 229.958984375, - "height": 40, - "autoResize": false, - "stereotypeLabel": { - "$ref": "AAAAAAFUv2n3Rs1i/NA=" - }, - "nameLabel": { - "$ref": "AAAAAAFUv2n3Rs1joWc=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFUv2n3Rs1k/4Q=" - }, - "propertyLabel": { - "$ref": "AAAAAAFUv2n3Rs1lmgQ=" - } - }, - { - "_type": "UMLLinePartView", - "_id": "AAAAAAFUv2n3Rs1mvsI=", - "_parent": { - "$ref": "AAAAAAFUv2n3Rc1gg3I=" - }, - "model": { - "$ref": "AAAAAAFUv2n3Rc1fbGI=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 715, - "top": 80, - "width": 1, - "height": 369, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 600, - "top": 40, - "width": 229.958984375, - "height": 409, - "autoResize": false, - "stereotypeDisplay": "label", - "showVisibility": true, - "showNamespace": false, - "showProperty": true, - "showType": true, - "nameCompartment": { - "$ref": "AAAAAAFUv2n3Rs1himo=" - }, - "wordWrap": false, - "linePart": { - "$ref": "AAAAAAFUv2n3Rs1mvsI=" - } - }, - { - "_type": "UMLSeqMessageView", - "_id": "AAAAAAFUv2qLR829xEQ=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFUv2qLR828Lgg=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv2qLSM2+Rpk=", - "_parent": { - "$ref": "AAAAAAFUv2qLR829xEQ=" - }, - "model": { - "$ref": "AAAAAAFUv2qLR828Lgg=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 82, - "top": 104, - "width": 153, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFUv2qLR829xEQ=" - }, - "edgePosition": 1, - "underline": false, - "text": "1 : sd_setImageWithURL()", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv2qLSM2/ZbI=", - "_parent": { - "$ref": "AAAAAAFUv2qLR829xEQ=" - }, - "model": { - "$ref": "AAAAAAFUv2qLR828Lgg=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 158, - "top": 89, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFUv2qLR829xEQ=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv2qLSM3A+iE=", - "_parent": { - "$ref": "AAAAAAFUv2qLR829xEQ=" - }, - "model": { - "$ref": "AAAAAAFUv2qLR828Lgg=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 158, - "top": 124, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFUv2qLR829xEQ=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "UMLActivationView", - "_id": "AAAAAAFUv2qLSM3BCds=", - "_parent": { - "$ref": "AAAAAAFUv2qLR829xEQ=" - }, - "model": { - "$ref": "AAAAAAFUv2qLR828Lgg=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 249, - "top": 120, - "width": 14, - "height": 29, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFUv2nXbM1HcJ0=" - }, - "tail": { - "$ref": "AAAAAAFUv2aETcyhhXc=" - }, - "lineStyle": 0, - "points": "68:120;249:120", - "nameLabel": { - "$ref": "AAAAAAFUv2qLSM2+Rpk=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFUv2qLSM2/ZbI=" - }, - "propertyLabel": { - "$ref": "AAAAAAFUv2qLSM3A+iE=" - }, - "activation": { - "$ref": "AAAAAAFUv2qLSM3BCds=" - }, - "showProperty": true, - "showType": true - }, - { - "_type": "UMLSeqLifelineView", - "_id": "AAAAAAFUv2ti0c3qqN0=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFUv2ti0c3pnPk=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFUv2ti0c3rcoE=", - "_parent": { - "$ref": "AAAAAAFUv2ti0c3qqN0=" - }, - "model": { - "$ref": "AAAAAAFUv2ti0c3pnPk=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFUv2ti0s3sWPY=", - "_parent": { - "$ref": "AAAAAAFUv2ti0c3rcoE=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -192, - "top": 0, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv2ti0s3tDyM=", - "_parent": { - "$ref": "AAAAAAFUv2ti0c3rcoE=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;1", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 845, - "top": 47, - "width": 174.23046875, - "height": 13, - "autoResize": false, - "underline": false, - "text": "Lifeline4: SDImageCache", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv2ti0s3uihE=", - "_parent": { - "$ref": "AAAAAAFUv2ti0c3rcoE=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -192, - "top": 0, - "width": 116.3779296875, - "height": 13, - "autoResize": false, - "underline": false, - "text": "(from Interaction1)", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv2ti0s3vC6k=", - "_parent": { - "$ref": "AAAAAAFUv2ti0c3rcoE=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -192, - "top": 0, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 1, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 840, - "top": 40, - "width": 184.23046875, - "height": 40, - "autoResize": false, - "stereotypeLabel": { - "$ref": "AAAAAAFUv2ti0s3sWPY=" - }, - "nameLabel": { - "$ref": "AAAAAAFUv2ti0s3tDyM=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFUv2ti0s3uihE=" - }, - "propertyLabel": { - "$ref": "AAAAAAFUv2ti0s3vC6k=" - } - }, - { - "_type": "UMLLinePartView", - "_id": "AAAAAAFUv2ti0s3wcIg=", - "_parent": { - "$ref": "AAAAAAFUv2ti0c3qqN0=" - }, - "model": { - "$ref": "AAAAAAFUv2ti0c3pnPk=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 932, - "top": 80, - "width": 1, - "height": 361, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 840, - "top": 40, - "width": 184.23046875, - "height": 401, - "autoResize": false, - "stereotypeDisplay": "label", - "showVisibility": true, - "showNamespace": false, - "showProperty": true, - "showType": true, - "nameCompartment": { - "$ref": "AAAAAAFUv2ti0c3rcoE=" - }, - "wordWrap": false, - "linePart": { - "$ref": "AAAAAAFUv2ti0s3wcIg=" - } - }, - { - "_type": "UMLSeqLifelineView", - "_id": "AAAAAAFUv22omM5CQm8=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFUv22omM5BZb4=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFUv22omM5DEW0=", - "_parent": { - "$ref": "AAAAAAFUv22omM5CQm8=" - }, - "model": { - "$ref": "AAAAAAFUv22omM5BZb4=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFUv22omc5E59M=", - "_parent": { - "$ref": "AAAAAAFUv22omM5DEW0=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -144, - "top": 0, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv22omc5FYM4=", - "_parent": { - "$ref": "AAAAAAFUv22omM5DEW0=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;1", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 1045, - "top": 47, - "width": 242.912109375, - "height": 13, - "autoResize": false, - "underline": false, - "text": "Lifeline5: SDWebImageDownloader", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv22omc5GELE=", - "_parent": { - "$ref": "AAAAAAFUv22omM5DEW0=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -144, - "top": 0, - "width": 116.3779296875, - "height": 13, - "autoResize": false, - "underline": false, - "text": "(from Interaction1)", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFUv22omc5HhQ8=", - "_parent": { - "$ref": "AAAAAAFUv22omM5DEW0=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -144, - "top": 0, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 1, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 1040, - "top": 40, - "width": 252.912109375, - "height": 40, - "autoResize": false, - "stereotypeLabel": { - "$ref": "AAAAAAFUv22omc5E59M=" - }, - "nameLabel": { - "$ref": "AAAAAAFUv22omc5FYM4=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFUv22omc5GELE=" - }, - "propertyLabel": { - "$ref": "AAAAAAFUv22omc5HhQ8=" - } - }, - { - "_type": "UMLLinePartView", - "_id": "AAAAAAFUv22omc5ImFY=", - "_parent": { - "$ref": "AAAAAAFUv22omM5CQm8=" - }, - "model": { - "$ref": "AAAAAAFUv22omM5BZb4=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 1166, - "top": 80, - "width": 1, - "height": 271, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 1040, - "top": 40, - "width": 252.912109375, - "height": 311, - "autoResize": false, - "stereotypeDisplay": "label", - "showVisibility": true, - "showNamespace": false, - "showProperty": true, - "showType": true, - "nameCompartment": { - "$ref": "AAAAAAFUv22omM5DEW0=" - }, - "wordWrap": false, - "linePart": { - "$ref": "AAAAAAFUv22omc5ImFY=" - } - }, - { - "_type": "UMLSeqMessageView", - "_id": "AAAAAAFXmw7K85hmo5Q=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFXmw7K8phl/ns=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFXmw7K85hnTgg=", - "_parent": { - "$ref": "AAAAAAFXmw7K85hmo5Q=" - }, - "model": { - "$ref": "AAAAAAFXmw7K8phl/ns=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 276, - "top": 120, - "width": 197, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFXmw7K85hmo5Q=" - }, - "edgePosition": 1, - "underline": false, - "text": "2 : sd_internalSetImageWithURL()", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFXmw7K85ho9qQ=", - "_parent": { - "$ref": "AAAAAAFXmw7K85hmo5Q=" - }, - "model": { - "$ref": "AAAAAAFXmw7K8phl/ns=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 374, - "top": 105, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFXmw7K85hmo5Q=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFXmw7K85hpBeU=", - "_parent": { - "$ref": "AAAAAAFXmw7K85hmo5Q=" - }, - "model": { - "$ref": "AAAAAAFXmw7K8phl/ns=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 374, - "top": 140, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFXmw7K85hmo5Q=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "UMLActivationView", - "_id": "AAAAAAFXmw7K85hqA4o=", - "_parent": { - "$ref": "AAAAAAFXmw7K85hmo5Q=" - }, - "model": { - "$ref": "AAAAAAFXmw7K8phl/ns=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 486, - "top": 136, - "width": 14, - "height": 29, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFXmwx1Rpf0Po8=" - }, - "tail": { - "$ref": "AAAAAAFUv2nXbM1HcJ0=" - }, - "lineStyle": 0, - "points": "262:136;486:136", - "nameLabel": { - "$ref": "AAAAAAFXmw7K85hnTgg=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFXmw7K85ho9qQ=" - }, - "propertyLabel": { - "$ref": "AAAAAAFXmw7K85hpBeU=" - }, - "activation": { - "$ref": "AAAAAAFXmw7K85hqA4o=" - }, - "showProperty": true, - "showType": true - }, - { - "_type": "UMLSeqMessageView", - "_id": "AAAAAAFXmw++VZh9CRk=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFXmw++VJh8ixo=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFXmw++VZh+iEI=", - "_parent": { - "$ref": "AAAAAAFXmw++VZh9CRk=" - }, - "model": { - "$ref": "AAAAAAFXmw++VJh8ixo=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 532, - "top": 136, - "width": 142, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFXmw++VZh9CRk=" - }, - "edgePosition": 1, - "underline": false, - "text": "3 : loadImageWithURL:()", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFXmw++VZh/8Ys=", - "_parent": { - "$ref": "AAAAAAFXmw++VZh9CRk=" - }, - "model": { - "$ref": "AAAAAAFXmw++VJh8ixo=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 603, - "top": 121, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFXmw++VZh9CRk=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFXmw++VZiAOKg=", - "_parent": { - "$ref": "AAAAAAFXmw++VZh9CRk=" - }, - "model": { - "$ref": "AAAAAAFXmw++VJh8ixo=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 603, - "top": 156, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFXmw++VZh9CRk=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "UMLActivationView", - "_id": "AAAAAAFXmw++VZiBUwE=", - "_parent": { - "$ref": "AAAAAAFXmw++VZh9CRk=" - }, - "model": { - "$ref": "AAAAAAFXmw++VJh8ixo=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 708, - "top": 152, - "width": 14, - "height": 29, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFUv2n3Rs1mvsI=" - }, - "tail": { - "$ref": "AAAAAAFXmwx1Rpf0Po8=" - }, - "lineStyle": 0, - "points": "499:152;708:152", - "nameLabel": { - "$ref": "AAAAAAFXmw++VZh+iEI=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFXmw++VZh/8Ys=" - }, - "propertyLabel": { - "$ref": "AAAAAAFXmw++VZiAOKg=" - }, - "activation": { - "$ref": "AAAAAAFXmw++VZiBUwE=" - }, - "showProperty": true, - "showType": true - }, - { - "_type": "UMLSeqMessageView", - "_id": "AAAAAAFUv2v1XM4K3QQ=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFUv2v1XM4JR/4=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv2v1XM4L7pY=", - "_parent": { - "$ref": "AAAAAAFUv2v1XM4K3QQ=" - }, - "model": { - "$ref": "AAAAAAFUv2v1XM4JR/4=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 741, - "top": 152, - "width": 164, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFUv2v1XM4K3QQ=" - }, - "edgePosition": 1, - "underline": false, - "text": "4 : queryDiskCacheForKey()", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv2v1Xc4MPnU=", - "_parent": { - "$ref": "AAAAAAFUv2v1XM4K3QQ=" - }, - "model": { - "$ref": "AAAAAAFUv2v1XM4JR/4=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 823, - "top": 137, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFUv2v1XM4K3QQ=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv2v1Xc4NX9s=", - "_parent": { - "$ref": "AAAAAAFUv2v1XM4K3QQ=" - }, - "model": { - "$ref": "AAAAAAFUv2v1XM4JR/4=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 823, - "top": 172, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFUv2v1XM4K3QQ=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "UMLActivationView", - "_id": "AAAAAAFUv2v1Xc4OIGU=", - "_parent": { - "$ref": "AAAAAAFUv2v1XM4K3QQ=" - }, - "model": { - "$ref": "AAAAAAFUv2v1XM4JR/4=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 925, - "top": 168, - "width": 14, - "height": 29, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFUv2ti0s3wcIg=" - }, - "tail": { - "$ref": "AAAAAAFUv2n3Rs1mvsI=" - }, - "lineStyle": 0, - "points": "721:168;925:168", - "nameLabel": { - "$ref": "AAAAAAFUv2v1XM4L7pY=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFUv2v1Xc4MPnU=" - }, - "propertyLabel": { - "$ref": "AAAAAAFUv2v1Xc4NX9s=" - }, - "activation": { - "$ref": "AAAAAAFUv2v1Xc4OIGU=" - }, - "showProperty": true, - "showType": true - }, - { - "_type": "UMLSeqMessageView", - "_id": "AAAAAAFUv2z30M4lNWE=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFUv2z3z84kqYU=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv2z30M4mUAU=", - "_parent": { - "$ref": "AAAAAAFUv2z30M4lNWE=" - }, - "model": { - "$ref": "AAAAAAFUv2z3z84kqYU=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 783, - "top": 212, - "width": 79, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFUv2z30M4lNWE=" - }, - "edgePosition": 1, - "underline": false, - "text": "5 : disk result", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv2z30M4nw8c=", - "_parent": { - "$ref": "AAAAAAFUv2z30M4lNWE=" - }, - "model": { - "$ref": "AAAAAAFUv2z3z84kqYU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 822, - "top": 227, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFUv2z30M4lNWE=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv2z30M4odbY=", - "_parent": { - "$ref": "AAAAAAFUv2z30M4lNWE=" - }, - "model": { - "$ref": "AAAAAAFUv2z3z84kqYU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 823, - "top": 192, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFUv2z30M4lNWE=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "UMLActivationView", - "_id": "AAAAAAFUv2z30c4pSow=", - "_parent": { - "$ref": "AAAAAAFUv2z30M4lNWE=" - }, - "model": { - "$ref": "AAAAAAFUv2z3z84kqYU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 715, - "top": 208, - "width": 14, - "height": 25, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFUv2n3Rs1mvsI=" - }, - "tail": { - "$ref": "AAAAAAFUv2ti0s3wcIg=" - }, - "lineStyle": 0, - "points": "932:208;715:208", - "nameLabel": { - "$ref": "AAAAAAFUv2z30M4mUAU=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFUv2z30M4nw8c=" - }, - "propertyLabel": { - "$ref": "AAAAAAFUv2z30M4odbY=" - }, - "activation": { - "$ref": "AAAAAAFUv2z30c4pSow=" - }, - "showProperty": true, - "showType": true - }, - { - "_type": "UMLSeqMessageView", - "_id": "AAAAAAFUv235TM5iC/o=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFUv235TM5h8OU=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv235Tc5jIuU=", - "_parent": { - "$ref": "AAAAAAFUv235TM5iC/o=" - }, - "model": { - "$ref": "AAAAAAFUv235TM5h8OU=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 784, - "top": 256, - "width": 307, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFUv235TM5iC/o=" - }, - "edgePosition": 1, - "underline": false, - "text": "6 : downloadImage(url, options, progress, completed)", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv235Tc5kvxw=", - "_parent": { - "$ref": "AAAAAAFUv235TM5iC/o=" - }, - "model": { - "$ref": "AAAAAAFUv235TM5h8OU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 937, - "top": 241, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFUv235TM5iC/o=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv235Tc5lN1Y=", - "_parent": { - "$ref": "AAAAAAFUv235TM5iC/o=" - }, - "model": { - "$ref": "AAAAAAFUv235TM5h8OU=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 937, - "top": 276, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFUv235TM5iC/o=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "UMLActivationView", - "_id": "AAAAAAFUv235Tc5mBt8=", - "_parent": { - "$ref": "AAAAAAFUv235TM5iC/o=" - }, - "model": { - "$ref": "AAAAAAFUv235TM5h8OU=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 1159, - "top": 272, - "width": 14, - "height": 29, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFUv22omc5ImFY=" - }, - "tail": { - "$ref": "AAAAAAFUv2n3Rs1mvsI=" - }, - "lineStyle": 0, - "points": "715:272;1159:272", - "nameLabel": { - "$ref": "AAAAAAFUv235Tc5jIuU=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFUv235Tc5kvxw=" - }, - "propertyLabel": { - "$ref": "AAAAAAFUv235Tc5lN1Y=" - }, - "activation": { - "$ref": "AAAAAAFUv235Tc5mBt8=" - }, - "showProperty": true, - "showType": true - }, - { - "_type": "UMLSeqMessageView", - "_id": "AAAAAAFUv27NWM56DH8=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFUv27NV855tyI=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv27NWM57KC8=", - "_parent": { - "$ref": "AAAAAAFUv27NWM56DH8=" - }, - "model": { - "$ref": "AAAAAAFUv27NV855tyI=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 967, - "top": 323, - "width": 100, - "height": 13, - "autoResize": false, - "alpha": 3.0124453800482693, - "distance": 77.64663547121665, - "hostEdge": { - "$ref": "AAAAAAFUv27NWM56DH8=" - }, - "edgePosition": 1, - "underline": false, - "text": "7 : network result", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv27NWM58Rks=", - "_parent": { - "$ref": "AAAAAAFUv27NWM56DH8=" - }, - "model": { - "$ref": "AAAAAAFUv27NV855tyI=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 939, - "top": 339, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFUv27NWM56DH8=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv27NWc59ep8=", - "_parent": { - "$ref": "AAAAAAFUv27NWM56DH8=" - }, - "model": { - "$ref": "AAAAAAFUv27NV855tyI=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 940, - "top": 304, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFUv27NWM56DH8=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "UMLActivationView", - "_id": "AAAAAAFUv27NWc5+otg=", - "_parent": { - "$ref": "AAAAAAFUv27NWM56DH8=" - }, - "model": { - "$ref": "AAAAAAFUv27NV855tyI=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 715, - "top": 320, - "width": 14, - "height": 25, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFUv2n3Rs1mvsI=" - }, - "tail": { - "$ref": "AAAAAAFUv22omc5ImFY=" - }, - "lineStyle": 0, - "points": "1166:320;715:320", - "nameLabel": { - "$ref": "AAAAAAFUv27NWM57KC8=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFUv27NWM58Rks=" - }, - "propertyLabel": { - "$ref": "AAAAAAFUv27NWc59ep8=" - }, - "activation": { - "$ref": "AAAAAAFUv27NWc5+otg=" - }, - "showProperty": true, - "showType": true - }, - { - "_type": "UMLSeqLifelineView", - "_id": "AAAAAAFXmwx1RpfuYEQ=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFXmwx1Rpft3W0=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFXmwx1Rpfvk4E=", - "_parent": { - "$ref": "AAAAAAFXmwx1RpfuYEQ=" - }, - "model": { - "$ref": "AAAAAAFXmwx1Rpft3W0=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFXmwx1Rpfwxbg=", - "_parent": { - "$ref": "AAAAAAFXmwx1Rpfvk4E=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -132, - "top": 0, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFXmwx1RpfxG9g=", - "_parent": { - "$ref": "AAAAAAFXmwx1Rpfvk4E=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;1", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 397, - "top": 47, - "width": 191, - "height": 13, - "autoResize": false, - "underline": false, - "text": "Lifeline2: UIView (WebCache)", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFXmwx1Rpfyq/k=", - "_parent": { - "$ref": "AAAAAAFXmwx1Rpfvk4E=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -132, - "top": 0, - "width": 106, - "height": 13, - "autoResize": false, - "underline": false, - "text": "(from Interaction1)", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "LabelView", - "_id": "AAAAAAFXmwx1RpfzQBw=", - "_parent": { - "$ref": "AAAAAAFXmwx1Rpfvk4E=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": -132, - "top": 0, - "width": 0, - "height": 13, - "autoResize": false, - "underline": false, - "horizontalAlignment": 1, - "verticalAlignment": 5, - "wordWrap": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 392, - "top": 40, - "width": 201, - "height": 40, - "autoResize": false, - "stereotypeLabel": { - "$ref": "AAAAAAFXmwx1Rpfwxbg=" - }, - "nameLabel": { - "$ref": "AAAAAAFXmwx1RpfxG9g=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFXmwx1Rpfyq/k=" - }, - "propertyLabel": { - "$ref": "AAAAAAFXmwx1RpfzQBw=" - } - }, - { - "_type": "UMLLinePartView", - "_id": "AAAAAAFXmwx1Rpf0Po8=", - "_parent": { - "$ref": "AAAAAAFXmwx1RpfuYEQ=" - }, - "model": { - "$ref": "AAAAAAFXmwx1Rpft3W0=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 493, - "top": 80, - "width": 1, - "height": 375, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 392, - "top": 40, - "width": 201, - "height": 415, - "autoResize": false, - "stereotypeDisplay": "label", - "showVisibility": true, - "showNamespace": false, - "showProperty": true, - "showType": true, - "nameCompartment": { - "$ref": "AAAAAAFXmwx1Rpfvk4E=" - }, - "wordWrap": false, - "linePart": { - "$ref": "AAAAAAFXmwx1Rpf0Po8=" - } - }, - { - "_type": "UMLSeqMessageView", - "_id": "AAAAAAFUv3C4p87cxD0=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFUv3C4p87b5L8=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv3C4qM7dheQ=", - "_parent": { - "$ref": "AAAAAAFUv3C4p87cxD0=" - }, - "model": { - "$ref": "AAAAAAFUv3C4p87b5L8=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 774, - "top": 353, - "width": 92, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFUv3C4p87cxD0=" - }, - "edgePosition": 1, - "underline": false, - "text": "8 : storeImage()", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv3C4qM7eLhs=", - "_parent": { - "$ref": "AAAAAAFUv3C4p87cxD0=" - }, - "model": { - "$ref": "AAAAAAFUv3C4p87b5L8=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 820, - "top": 338, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFUv3C4p87cxD0=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFUv3C4qM7fGpA=", - "_parent": { - "$ref": "AAAAAAFUv3C4p87cxD0=" - }, - "model": { - "$ref": "AAAAAAFUv3C4p87b5L8=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 820, - "top": 373, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFUv3C4p87cxD0=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "UMLActivationView", - "_id": "AAAAAAFUv3C4qM7gDWs=", - "_parent": { - "$ref": "AAAAAAFUv3C4p87cxD0=" - }, - "model": { - "$ref": "AAAAAAFUv3C4p87b5L8=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 925, - "top": 369, - "width": 14, - "height": 29, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFUv2ti0s3wcIg=" - }, - "tail": { - "$ref": "AAAAAAFUv2n3Rs1mvsI=" - }, - "lineStyle": 0, - "points": "715:369;925:369", - "nameLabel": { - "$ref": "AAAAAAFUv3C4qM7dheQ=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFUv3C4qM7eLhs=" - }, - "propertyLabel": { - "$ref": "AAAAAAFUv3C4qM7fGpA=" - }, - "activation": { - "$ref": "AAAAAAFUv3C4qM7gDWs=" - }, - "showProperty": true, - "showType": true - }, - { - "_type": "UMLSeqMessageView", - "_id": "AAAAAAFXmxBoRJiUpvI=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFXmxBoRJiTAtY=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFXmxBoRZiVYHw=", - "_parent": { - "$ref": "AAAAAAFXmxBoRJiUpvI=" - }, - "model": { - "$ref": "AAAAAAFXmxBoRJiTAtY=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 576, - "top": 404, - "width": 54, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFXmxBoRJiUpvI=" - }, - "edgePosition": 1, - "underline": false, - "text": "9 : image", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFXmxBoRZiWIYg=", - "_parent": { - "$ref": "AAAAAAFXmxBoRJiUpvI=" - }, - "model": { - "$ref": "AAAAAAFXmxBoRJiTAtY=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 603, - "top": 419, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFXmxBoRJiUpvI=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFXmxBoRZiXh28=", - "_parent": { - "$ref": "AAAAAAFXmxBoRJiUpvI=" - }, - "model": { - "$ref": "AAAAAAFXmxBoRJiTAtY=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 604, - "top": 384, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFXmxBoRJiUpvI=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "UMLActivationView", - "_id": "AAAAAAFXmxBoRZiYI2g=", - "_parent": { - "$ref": "AAAAAAFXmxBoRJiUpvI=" - }, - "model": { - "$ref": "AAAAAAFXmxBoRJiTAtY=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 493, - "top": 400, - "width": 14, - "height": 25, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFXmwx1Rpf0Po8=" - }, - "tail": { - "$ref": "AAAAAAFUv2n3Rs1mvsI=" - }, - "lineStyle": 0, - "points": "715:400;493:400", - "nameLabel": { - "$ref": "AAAAAAFXmxBoRZiVYHw=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFXmxBoRZiWIYg=" - }, - "propertyLabel": { - "$ref": "AAAAAAFXmxBoRZiXh28=" - }, - "activation": { - "$ref": "AAAAAAFXmxBoRZiYI2g=" - }, - "showProperty": true, - "showType": true - }, - { - "_type": "UMLSeqMessageView", - "_id": "AAAAAAFXmxC8H5jJURo=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozTHHk=" - }, - "model": { - "$ref": "AAAAAAFXmxC8H5jIbu4=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFXmxC8H5jKD8g=", - "_parent": { - "$ref": "AAAAAAFXmxC8H5jJURo=" - }, - "model": { - "$ref": "AAAAAAFXmxC8H5jIbu4=" - }, - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 332, - "top": 428, - "width": 83, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFXmxC8H5jJURo=" - }, - "edgePosition": 1, - "underline": false, - "text": "10 : set image", - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFXmxC8H5jLiWU=", - "_parent": { - "$ref": "AAAAAAFXmxC8H5jJURo=" - }, - "model": { - "$ref": "AAAAAAFXmxC8H5jIbu4=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 373, - "top": 443, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": 1.5707963267948966, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFXmxC8H5jJURo=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFXmxC8H5jMFqs=", - "_parent": { - "$ref": "AAAAAAFXmxC8H5jJURo=" - }, - "model": { - "$ref": "AAAAAAFXmxC8H5jIbu4=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 374, - "top": 408, - "width": 0, - "height": 13, - "autoResize": false, - "alpha": -1.5707963267948966, - "distance": 10, - "hostEdge": { - "$ref": "AAAAAAFXmxC8H5jJURo=" - }, - "edgePosition": 1, - "underline": false, - "horizontalAlignment": 2, - "verticalAlignment": 5, - "wordWrap": false - }, - { - "_type": "UMLActivationView", - "_id": "AAAAAAFXmxC8H5jNKho=", - "_parent": { - "$ref": "AAAAAAFXmxC8H5jJURo=" - }, - "model": { - "$ref": "AAAAAAFXmxC8H5jIbu4=" - }, - "visible": false, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "left": 256, - "top": 424, - "width": 14, - "height": 25, - "autoResize": false - } - ], - "visible": true, - "enabled": true, - "lineColor": "#000000", - "fillColor": "#ffffff", - "fontColor": "#000000", - "font": "Arial;13;0", - "showShadow": true, - "containerChangeable": false, - "containerExtending": false, - "head": { - "$ref": "AAAAAAFUv2nXbM1HcJ0=" - }, - "tail": { - "$ref": "AAAAAAFXmwx1Rpf0Po8=" - }, - "lineStyle": 0, - "points": "493:424;256:424", - "nameLabel": { - "$ref": "AAAAAAFXmxC8H5jKD8g=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFXmxC8H5jLiWU=" - }, - "propertyLabel": { - "$ref": "AAAAAAFXmxC8H5jMFqs=" - }, - "activation": { - "$ref": "AAAAAAFXmxC8H5jNKho=" - }, - "showProperty": true, - "showType": true - } - ], - "showSequenceNumber": true, - "showSignature": true, - "showActivation": true - } - ], - "visibility": "public", - "isReentrant": true, - "messages": [ - { - "_type": "UMLMessage", - "_id": "AAAAAAFUv2qLR828Lgg=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "Message1", - "source": { - "$ref": "AAAAAAFUv2aES8yaBvg=" - }, - "target": { - "$ref": "AAAAAAFUv2nXaM1AL0k=" - }, - "visibility": "public", - "messageSort": "asynchCall", - "signature": { - "$ref": "AAAAAAFUmPuK4C6yWrI=" - }, - "isConcurrentIteration": false - }, - { - "_type": "UMLMessage", - "_id": "AAAAAAFXmw7K8phl/ns=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "Message2", - "source": { - "$ref": "AAAAAAFUv2nXaM1AL0k=" - }, - "target": { - "$ref": "AAAAAAFXmwx1Rpft3W0=" - }, - "visibility": "public", - "messageSort": "asynchCall", - "signature": { - "$ref": "AAAAAAFXmsqK3idvzv0=" - }, - "isConcurrentIteration": false - }, - { - "_type": "UMLMessage", - "_id": "AAAAAAFXmw++VJh8ixo=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "Message6", - "source": { - "$ref": "AAAAAAFXmwx1Rpft3W0=" - }, - "target": { - "$ref": "AAAAAAFUv2n3Rc1fbGI=" - }, - "visibility": "public", - "messageSort": "asynchCall", - "signature": { - "$ref": "AAAAAAFUkh/xZ44AqYk=" - }, - "isConcurrentIteration": false - }, - { - "_type": "UMLMessage", - "_id": "AAAAAAFUv2v1XM4JR/4=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "Message3", - "source": { - "$ref": "AAAAAAFUv2n3Rc1fbGI=" - }, - "target": { - "$ref": "AAAAAAFUv2ti0c3pnPk=" - }, - "visibility": "public", - "messageSort": "asynchCall", - "signature": { - "$ref": "AAAAAAFUmPN5KSOfrIg=" - }, - "isConcurrentIteration": false - }, - { - "_type": "UMLMessage", - "_id": "AAAAAAFUv2z3z84kqYU=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "disk result", - "source": { - "$ref": "AAAAAAFUv2ti0c3pnPk=" - }, - "target": { - "$ref": "AAAAAAFUv2n3Rc1fbGI=" - }, - "visibility": "public", - "messageSort": "reply", - "isConcurrentIteration": false - }, - { - "_type": "UMLMessage", - "_id": "AAAAAAFUv235TM5h8OU=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "Message4", - "source": { - "$ref": "AAAAAAFUv2n3Rc1fbGI=" - }, - "target": { - "$ref": "AAAAAAFUv22omM5BZb4=" - }, - "visibility": "public", - "messageSort": "asynchCall", - "signature": { - "$ref": "AAAAAAFUmOOite2pkfo=" - }, - "isConcurrentIteration": false - }, - { - "_type": "UMLMessage", - "_id": "AAAAAAFUv27NV855tyI=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "network result", - "source": { - "$ref": "AAAAAAFUv22omM5BZb4=" - }, - "target": { - "$ref": "AAAAAAFUv2n3Rc1fbGI=" - }, - "visibility": "public", - "messageSort": "reply", - "isConcurrentIteration": false - }, - { - "_type": "UMLMessage", - "_id": "AAAAAAFUv3C4p87b5L8=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "Message5", - "source": { - "$ref": "AAAAAAFUv2n3Rc1fbGI=" - }, - "target": { - "$ref": "AAAAAAFUv2ti0c3pnPk=" - }, - "visibility": "public", - "messageSort": "synchCall", - "signature": { - "$ref": "AAAAAAFUmPMOWiHsOa0=" - }, - "isConcurrentIteration": false - }, - { - "_type": "UMLMessage", - "_id": "AAAAAAFXmxBoRJiTAtY=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "image", - "source": { - "$ref": "AAAAAAFUv2n3Rc1fbGI=" - }, - "target": { - "$ref": "AAAAAAFXmwx1Rpft3W0=" - }, - "visibility": "public", - "messageSort": "reply", - "isConcurrentIteration": false - }, - { - "_type": "UMLMessage", - "_id": "AAAAAAFXmxC8H5jIbu4=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "set image", - "source": { - "$ref": "AAAAAAFXmwx1Rpft3W0=" - }, - "target": { - "$ref": "AAAAAAFUv2nXaM1AL0k=" - }, - "visibility": "public", - "messageSort": "reply", - "isConcurrentIteration": false - } - ], - "participants": [ - { - "_type": "UMLLifeline", - "_id": "AAAAAAFUv2aES8yaBvg=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "Other object", - "visibility": "public", - "represent": { - "$ref": "AAAAAAFUv2aES8yZWGo=" - }, - "isMultiInstance": false - }, - { - "_type": "UMLLifeline", - "_id": "AAAAAAFUv2nXaM1AL0k=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "Lifeline1", - "visibility": "public", - "represent": { - "$ref": "AAAAAAFUv2nXZ80/4sA=" - }, - "isMultiInstance": false - }, - { - "_type": "UMLLifeline", - "_id": "AAAAAAFUv2n3Rc1fbGI=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "Lifeline3", - "visibility": "public", - "represent": { - "$ref": "AAAAAAFUv2n3Rc1e9QI=" - }, - "isMultiInstance": false - }, - { - "_type": "UMLLifeline", - "_id": "AAAAAAFUv2ti0c3pnPk=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "Lifeline4", - "visibility": "public", - "represent": { - "$ref": "AAAAAAFUv2ti0c3ocQo=" - }, - "isMultiInstance": false - }, - { - "_type": "UMLLifeline", - "_id": "AAAAAAFUv22omM5BZb4=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "Lifeline5", - "visibility": "public", - "represent": { - "$ref": "AAAAAAFUv22ol85ADFk=" - }, - "isMultiInstance": false - }, - { - "_type": "UMLLifeline", - "_id": "AAAAAAFXmwx1Rpft3W0=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozSZjs=" - }, - "name": "Lifeline2", - "visibility": "public", - "represent": { - "$ref": "AAAAAAFXmwx1Rpfs4dU=" - }, - "isMultiInstance": false - } - ] - } - ], - "visibility": "public", - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUv2HAQMvkinw=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozRCy8=" - }, - "name": "Role1", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUv2UwYMxGW0c=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozRCy8=" - }, - "name": "Role2", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUv2aES8yZWGo=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozRCy8=" - }, - "name": "Role3", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUv2dCAMzP0O0=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozRCy8=" - }, - "name": "Role4", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUv2nXZ80/4sA=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozRCy8=" - }, - "name": "Role5", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": { - "$ref": "AAAAAAFUmPtmMC6BqlU=" - }, - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUv2n3Rc1e9QI=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozRCy8=" - }, - "name": "Role6", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUv2ti0c3ocQo=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozRCy8=" - }, - "name": "Role7", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUv22ol85ADFk=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozRCy8=" - }, - "name": "Role8", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFXmwx1Rpfs4dU=", - "_parent": { - "$ref": "AAAAAAFUkhaWOozRCy8=" - }, - "name": "Role9", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": { - "$ref": "AAAAAAFXmsqK3SdrXmw=" - }, - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false - }, - { - "_type": "UMLPackage", - "_id": "AAAAAAFUkhbx4ozg49g=", - "_parent": { - "$ref": "AAAAAAFF+qBWK6M3Z8Y=" - }, - "name": "SDWebImage", - "ownedElements": [ - { - "_type": "UMLClass", - "_id": "AAAAAAFUkhgItozoKPM=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImagePrefetcher", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFUmMzgZcn8MSQ=", - "_parent": { - "$ref": "AAAAAAFUkhgItozoKPM=" - }, - "name": "manager", - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFUmMzgZsn92Qw=", - "_parent": { - "$ref": "AAAAAAFUmMzgZcn8MSQ=" - }, - "reference": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "none", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFUmMzgZsn+nz8=", - "_parent": { - "$ref": "AAAAAAFUmMzgZcn8MSQ=" - }, - "reference": { - "$ref": "AAAAAAFUkhgItozoKPM=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "shared", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "visibility": "public", - "isDerived": false - }, - { - "_type": "UMLAssociation", - "_id": "AAAAAAFUmM8TqsupT40=", - "_parent": { - "$ref": "AAAAAAFUkhgItozoKPM=" - }, - "name": "delegate", - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFUmM8Tqsuqc7A=", - "_parent": { - "$ref": "AAAAAAFUmM8TqsupT40=" - }, - "reference": { - "$ref": "AAAAAAFUkhg5/4zs5zU=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "none", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFUmM8Tqsuru94=", - "_parent": { - "$ref": "AAAAAAFUmM8TqsupT40=" - }, - "reference": { - "$ref": "AAAAAAFUkhgItozoKPM=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "shared", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "visibility": "public", - "isDerived": false - } - ], - "visibility": "public", - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmM4zy8syqFU=", - "_parent": { - "$ref": "AAAAAAFUkhgItozoKPM=" - }, - "name": "sharedImagePrefetcher", - "visibility": "public", - "isStatic": true, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmMwm7Mnxz9U=", - "_parent": { - "$ref": "AAAAAAFUkhgItozoKPM=" - }, - "name": "options", - "stereotype": "", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": { - "$ref": "AAAAAAFUkhyNUo23oFw=" - }, - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmM3dVsr1bHY=", - "_parent": { - "$ref": "AAAAAAFUkhgItozoKPM=" - }, - "name": "prefetchURLs:", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmNCMgs5kwbc=", - "_parent": { - "$ref": "AAAAAAFUkhgItozoKPM=" - }, - "name": "cancelPrefetching", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLInterface", - "_id": "AAAAAAFXmwdRJMUYGTs=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageDownloaderOperationInterface", - "visibility": "public", - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false - }, - { - "_type": "UMLInterface", - "_id": "AAAAAAFUkhg5/4zs5zU=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImagePrefetcherDelegate", - "visibility": "public", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFUkht/NI1jZE4=", - "_parent": { - "$ref": "AAAAAAFUkhg5/4zs5zU=" - }, - "name": "didPrefetchURL:", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUkhu8u41n4Ps=", - "_parent": { - "$ref": "AAAAAAFUkhg5/4zs5zU=" - }, - "name": "didFinishWithTotalCount:", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFUkhwuq42z3w4=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageManager", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFUmNGSiNAIwc4=", - "_parent": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "name": "delegate", - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFUmNGSiNAJw9E=", - "_parent": { - "$ref": "AAAAAAFUmNGSiNAIwc4=" - }, - "reference": { - "$ref": "AAAAAAFUkh5jeI3spbg=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "none", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFUmNGSiNAKXzo=", - "_parent": { - "$ref": "AAAAAAFUmNGSiNAIwc4=" - }, - "reference": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "shared", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "visibility": "public", - "isDerived": false - }, - { - "_type": "UMLAssociation", - "_id": "AAAAAAFUmNgnHdueiaU=", - "_parent": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "name": "imageCache", - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFUmNgnHdufJSY=", - "_parent": { - "$ref": "AAAAAAFUmNgnHdueiaU=" - }, - "reference": { - "$ref": "AAAAAAFXmwGn6ZeqpYw=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "none", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFUmNgnHdugw8c=", - "_parent": { - "$ref": "AAAAAAFUmNgnHdueiaU=" - }, - "reference": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "shared", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "visibility": "public", - "isDerived": false - }, - { - "_type": "UMLAssociation", - "_id": "AAAAAAFUmNjLG94yKqE=", - "_parent": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFUmNjLG94zD4E=", - "_parent": { - "$ref": "AAAAAAFUmNjLG94yKqE=" - }, - "reference": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "none", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFUmNjLG940ssQ=", - "_parent": { - "$ref": "AAAAAAFUmNjLG94yKqE=" - }, - "reference": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "shared", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "visibility": "public", - "isDerived": false - } - ], - "visibility": "public", - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUkiBj3o4EzZs=", - "_parent": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "name": "sharedManager", - "visibility": "public", - "isStatic": true, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmMkoD8jx3Dk=", - "_parent": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "name": "options", - "stereotype": "", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": { - "$ref": "AAAAAAFUkhyNUo23oFw=" - }, - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFUkh/xZ44AqYk=", - "_parent": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "name": "loadImageWithURL:", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFUmNYJLthMwcI=", - "_parent": { - "$ref": "AAAAAAFUkh/xZ44AqYk=" - }, - "name": "Parameter1", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": { - "$ref": "AAAAAAFUmNVIhta461s=" - }, - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "return" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmNLHKNJpLPM=", - "_parent": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "name": "saveImageToCache:", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmNLtYNLc08o=", - "_parent": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "name": "cancelAll", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmNNJv9NPrNI=", - "_parent": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "name": "cachedImageExistsForURL", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFUmNPQf9Tw0fM=", - "_parent": { - "$ref": "AAAAAAFUmNNJv9NPrNI=" - }, - "name": "Parameter1", - "stereotype": "", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "BOOL", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "return" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmNNp59PCdv8=", - "_parent": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "name": "diskImageExistsForURL", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFUmNaUldjqLy4=", - "_parent": { - "$ref": "AAAAAAFUmNNp59PCdv8=" - }, - "name": "Parameter1", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "BOOL", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "return" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmNORx9Q1mi4=", - "_parent": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "name": "cacheKeyForURL", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFUmNbDrdlJMIU=", - "_parent": { - "$ref": "AAAAAAFUmNORx9Q1mi4=" - }, - "name": "Parameter1", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "NSString", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "return" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLEnumeration", - "_id": "AAAAAAFUkhyNUo23oFw=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageOptions", - "visibility": "public", - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "literals": [ - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkhys4o27Ge0=", - "_parent": { - "$ref": "AAAAAAFUkhyNUo23oFw=" - }, - "name": "SDWebImageRetryFailed", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkhza8o2/z9E=", - "_parent": { - "$ref": "AAAAAAFUkhyNUo23oFw=" - }, - "name": "SDWebImageLowPriority", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkhzkGo3CNk8=", - "_parent": { - "$ref": "AAAAAAFUkhyNUo23oFw=" - }, - "name": "SDWebImageCacheMemoryOnly", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkhzs8o3Fkdk=", - "_parent": { - "$ref": "AAAAAAFUkhyNUo23oFw=" - }, - "name": "SDWebImageProgressiveLoad", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkhz04o3ItAc=", - "_parent": { - "$ref": "AAAAAAFUkhyNUo23oFw=" - }, - "name": "SDWebImageRefreshCached", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkhz84Y3L96A=", - "_parent": { - "$ref": "AAAAAAFUkhyNUo23oFw=" - }, - "name": "SDWebImageContinueInBackground", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkh0C6Y3O214=", - "_parent": { - "$ref": "AAAAAAFUkhyNUo23oFw=" - }, - "name": "SDWebImageHandleCookies", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkh2TUY3YpnQ=", - "_parent": { - "$ref": "AAAAAAFUkhyNUo23oFw=" - }, - "name": "SDWebImageAllowInvalidSSLCertificates", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkh2bqY3bxlE=", - "_parent": { - "$ref": "AAAAAAFUkhyNUo23oFw=" - }, - "name": "SDWebImageHighPriority", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkh2p4Y3e22E=", - "_parent": { - "$ref": "AAAAAAFUkhyNUo23oFw=" - }, - "name": "SDWebImageDelayPlaceholder", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkh2x+Y3hQmw=", - "_parent": { - "$ref": "AAAAAAFUkhyNUo23oFw=" - }, - "name": "SDWebImageTransformAnimatedImage", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkh31iY3ox50=", - "_parent": { - "$ref": "AAAAAAFUkhyNUo23oFw=" - }, - "name": "SDWebImageAvoidAutoSetImage", - "visibility": "public" - } - ] - }, - { - "_type": "UMLInterface", - "_id": "AAAAAAFUkh5jeI3spbg=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageManagerDelegate", - "visibility": "public", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFUkh6LiI3wgxM=", - "_parent": { - "$ref": "AAAAAAFUkh5jeI3spbg=" - }, - "name": "shouldDownloadImageForURL:", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUkh65uI30vRk=", - "_parent": { - "$ref": "AAAAAAFUkh5jeI3spbg=" - }, - "name": "transformDownloadedImage:", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFUkh79WI34fB0=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDImageCache", - "ownedElements": [ - { - "_type": "UMLDependency", - "_id": "AAAAAAFfKuwBKAhI5QU=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "source": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "target": { - "$ref": "AAAAAAFfKukEJfyENXE=" - }, - "visibility": "public" - } - ], - "visibility": "public", - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUkiFzJY5gThM=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "sharedImageCache", - "visibility": "public", - "isStatic": true, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmPDC7hpSvPQ=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "maxMemoryCost", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmPDhrRsNyCc=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "maxMemoryCountLimit", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPGStR3F538=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "init", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFUmPG3vB5TsDQ=", - "_parent": { - "$ref": "AAAAAAFUmPGStR3F538=" - }, - "name": "namespace", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPHYnB7PNs4=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "init", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFUmPHujB9dtv8=", - "_parent": { - "$ref": "AAAAAAFUmPHYnB7PNs4=" - }, - "name": "namespace", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFUmPH10x+6tbo=", - "_parent": { - "$ref": "AAAAAAFUmPHYnB7PNs4=" - }, - "name": "diskCacheDirectory", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPMOWiHsOa0=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "storeImage", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPMtQiKnVfM=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "storeImageDataToDisk", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPN5KSOfrIg=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "queryDiskCacheForKey", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPOk0iRaSME=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "imageFromMemoryCacheForKey", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPPBiSUVHSU=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "imageFromDiskCacheForKey", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPPiwSXQs7U=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "removeImageForKey", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPQzYSaLCQc=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "clearMemory", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPRYYSdGCZA=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "clearDIsk", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPTT0CgBzK8=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "cachePathForKey", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPT4WSi8pg0=", - "_parent": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "name": "addReadOnlyCachePath", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFXmwGn6ZeqpYw=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDImageCacheConfig", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFXmwYAOLO3R8M=", - "_parent": { - "$ref": "AAAAAAFXmwGn6ZeqpYw=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFXmwYAOLO4X9g=", - "_parent": { - "$ref": "AAAAAAFXmwYAOLO3R8M=" - }, - "reference": { - "$ref": "AAAAAAFXmwGn6ZeqpYw=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "none", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFXmwYAOLO5TNo=", - "_parent": { - "$ref": "AAAAAAFXmwYAOLO3R8M=" - }, - "name": "config", - "reference": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "shared", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "visibility": "public", - "isDerived": false - } - ], - "visibility": "public", - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmPBKVhghKWk=", - "_parent": { - "$ref": "AAAAAAFXmwGn6ZeqpYw=" - }, - "name": "shouldDecompressImages", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmPBxrhjcaQc=", - "_parent": { - "$ref": "AAAAAAFXmwGn6ZeqpYw=" - }, - "name": "shouldDisableiCloud", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmPCLlRmXEPs=", - "_parent": { - "$ref": "AAAAAAFXmwGn6ZeqpYw=" - }, - "name": "shouldCacheImagesInMemory", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmPD+pRvI9sU=", - "_parent": { - "$ref": "AAAAAAFXmwGn6ZeqpYw=" - }, - "name": "maxCacheAge", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmPEdRRyDmKo=", - "_parent": { - "$ref": "AAAAAAFXmwGn6ZeqpYw=" - }, - "name": "maxCacheSize", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFUkh8UMI38gtY=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageDownloader", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFUmNjw298aBP0=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "name": "imageDownloader", - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFUmNjw298bVKc=", - "_parent": { - "$ref": "AAAAAAFUmNjw298aBP0=" - }, - "reference": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "none", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFUmNjw298cZas=", - "_parent": { - "$ref": "AAAAAAFUmNjw298aBP0=" - }, - "reference": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "shared", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "visibility": "public", - "isDerived": false - }, - { - "_type": "UMLDependency", - "_id": "AAAAAAFUmOrfAwPdh8M=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "source": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "target": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "visibility": "public" - }, - { - "_type": "UMLDependency", - "_id": "AAAAAAFfKuxM+AnptLY=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "source": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "target": { - "$ref": "AAAAAAFfKukEJfyENXE=" - }, - "visibility": "public" - } - ], - "visibility": "public", - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUkiJAhI5kL78=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "name": "sharedDownloader", - "visibility": "public", - "isStatic": true, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmOMr1ewzvaI=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "name": "shouldDecompressImages", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmONDtOzuN2c=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "name": "maxConcurrentDownloads", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmOaPcvo7CuM=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "name": "downloadTimeout", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmOa7+/r2ysU=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "name": "executionOrder", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmOiCz/5aGv0=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "name": "urlCredential", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFXmuCdynfN50Y=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "name": "init", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFXmuEYDHj2f9E=", - "_parent": { - "$ref": "AAAAAAFXmuCdynfN50Y=" - }, - "name": "sessionConfiguration", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmOOite2pkfo=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "name": "downloadImage", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFUmOW7A/c+Z/0=", - "_parent": { - "$ref": "AAAAAAFUmOOite2pkfo=" - }, - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": { - "$ref": "AAAAAAFXmuJtT3q/PXo=" - }, - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "return" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFXmuK8y3sdotY=", - "_parent": { - "$ref": "AAAAAAFUmOOite2pkfo=" - }, - "name": "url", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFXmuLgMHuZcI8=", - "_parent": { - "$ref": "AAAAAAFUmOOite2pkfo=" - }, - "name": "options", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFXmuMLQXwVkMM=", - "_parent": { - "$ref": "AAAAAAFUmOOite2pkfo=" - }, - "name": "progress", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFXmuM7iXyR7gc=", - "_parent": { - "$ref": "AAAAAAFUmOOite2pkfo=" - }, - "name": "completed", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFXmuQArX//uuI=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "name": "cancel", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFXmuQ4uoEJf7Q=", - "_parent": { - "$ref": "AAAAAAFXmuQArX//uuI=" - }, - "name": "token", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmOZtsvmAcFQ=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "name": "currentDownloadCount", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmOeh6PwLtkk=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "name": "setValueForHTTPHeaderField", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmOf3GPzGjm4=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "name": "setSuspended", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmOgcH/2BRjw=", - "_parent": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "name": "cancelAllDownloads", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLEnumeration", - "_id": "AAAAAAFUkiDjJo5QvT4=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDImageCacheType", - "visibility": "public", - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "literals": [ - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkiD+ro5UDPI=", - "_parent": { - "$ref": "AAAAAAFUkiDjJo5QvT4=" - }, - "name": "SDImageCacheTypeNone", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkiEOJo5YAWk=", - "_parent": { - "$ref": "AAAAAAFUkiDjJo5QvT4=" - }, - "name": "SDImageCacheTypeDisk", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUkiEUdY5bs1I=", - "_parent": { - "$ref": "AAAAAAFUkiDjJo5QvT4=" - }, - "name": "SDImageCacheTypeMemory", - "visibility": "public" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFXmuJtT3q/PXo=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageDownloadToken", - "ownedElements": [ - { - "_type": "UMLDependency", - "_id": "AAAAAAFXmuZ1booW7c8=", - "_parent": { - "$ref": "AAAAAAFXmuJtT3q/PXo=" - }, - "source": { - "$ref": "AAAAAAFUkh8UMI38gtY=" - }, - "target": { - "$ref": "AAAAAAFXmuJtT3q/PXo=" - }, - "visibility": "public" - } - ], - "visibility": "public", - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFXmuY4yIivPbY=", - "_parent": { - "$ref": "AAAAAAFXmuJtT3q/PXo=" - }, - "name": "url", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFXmuZPjolqbRg=", - "_parent": { - "$ref": "AAAAAAFXmuJtT3q/PXo=" - }, - "name": "downloadOperationCancelToken", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFUkiR/Go5pUW0=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageDownloaderOperation", - "ownedElements": [ - { - "_type": "UMLInterfaceRealization", - "_id": "AAAAAAFUmORm3fAwE60=", - "_parent": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "source": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "target": { - "$ref": "AAAAAAFXmwdRJMUYGTs=" - }, - "visibility": "public" - }, - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFUmOy6gwh7Mto=", - "_parent": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "source": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "target": { - "$ref": "AAAAAAFUmOxnEwduTCw=" - }, - "visibility": "public" - } - ], - "visibility": "public", - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmO0bSwoHlgM=", - "_parent": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "name": "request", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmO4eABBktMs=", - "_parent": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "name": "response", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmO04OQrC3XA=", - "_parent": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "name": "shouldDecompressImages", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmO1WCQt9gzI=", - "_parent": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "name": "shouldUseCredentialStorage", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmO1nCQw4ACs=", - "_parent": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "name": "credential", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFUmO2TmQzzs/g=", - "_parent": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "name": "options", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": { - "$ref": "AAAAAAFUmOC2fugTUX8=" - }, - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFXmt1lVW0nz6U=", - "_parent": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "name": "dataTask", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmO55eBHmK5M=", - "_parent": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "name": "init", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFUmO7d6BKxVI0=", - "_parent": { - "$ref": "AAAAAAFUmO55eBHmK5M=" - }, - "name": "request", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFXmt4TNm7JJVo=", - "_parent": { - "$ref": "AAAAAAFUmO55eBHmK5M=" - }, - "name": "session", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFUmO731xMtljo=", - "_parent": { - "$ref": "AAAAAAFUmO55eBHmK5M=" - }, - "name": "options", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFXmt5iT2+ClWI=", - "_parent": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "name": "addHandlers", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFXmt6z23BNV0g=", - "_parent": { - "$ref": "AAAAAAFXmt5iT2+ClWI=" - }, - "name": "progressBlock", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFXmt7YlXDJ9ls=", - "_parent": { - "$ref": "AAAAAAFXmt5iT2+ClWI=" - }, - "name": "completedBlock", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFXmt9bf3FF/EU=", - "_parent": { - "$ref": "AAAAAAFUkiR/Go5pUW0=" - }, - "name": "cancel", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLInterface", - "_id": "AAAAAAFUmNVIhta461s=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageOperation", - "visibility": "public", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmNWHXtbX7L0=", - "_parent": { - "$ref": "AAAAAAFUmNVIhta461s=" - }, - "name": "cancel", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFUmN6ZSOUCaRM=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageCombinedOperation", - "ownedElements": [ - { - "_type": "UMLInterfaceRealization", - "_id": "AAAAAAFUmN83duYfrao=", - "_parent": { - "$ref": "AAAAAAFUmN6ZSOUCaRM=" - }, - "source": { - "$ref": "AAAAAAFUmN6ZSOUCaRM=" - }, - "target": { - "$ref": "AAAAAAFUmNVIhta461s=" - }, - "visibility": "public" - } - ], - "visibility": "public", - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLEnumeration", - "_id": "AAAAAAFUmOC2fugTUX8=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageDownloaderOptions", - "visibility": "public", - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "literals": [ - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUmODurehEneQ=", - "_parent": { - "$ref": "AAAAAAFUmOC2fugTUX8=" - }, - "name": "SDWebImageDownloaderLowPriority", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUmOD23ehlAns=", - "_parent": { - "$ref": "AAAAAAFUmOC2fugTUX8=" - }, - "name": "SDWebImageDownloaderProgressiveDownload", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUmOD+neiGg3g=", - "_parent": { - "$ref": "AAAAAAFUmOC2fugTUX8=" - }, - "name": "SDWebImageDownloaderUseNSURLCache", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUmOEGbeinNtM=", - "_parent": { - "$ref": "AAAAAAFUmOC2fugTUX8=" - }, - "name": "SDWebImageDownloaderIgnoreCachedResponse", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUmOENpujIT/I=", - "_parent": { - "$ref": "AAAAAAFUmOC2fugTUX8=" - }, - "name": "SDWebImageDownloaderContinueInBackground", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUmOEVzujp/Q0=", - "_parent": { - "$ref": "AAAAAAFUmOC2fugTUX8=" - }, - "name": "SDWebImageDownloaderHandleCookies", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUmOEc/ekKMBo=", - "_parent": { - "$ref": "AAAAAAFUmOC2fugTUX8=" - }, - "name": "SDWebImageDownloaderAllowInvalidSSLCertificates", - "visibility": "public" - }, - { - "_type": "UMLEnumerationLiteral", - "_id": "AAAAAAFUmOEkLekrSQE=", - "_parent": { - "$ref": "AAAAAAFUmOC2fugTUX8=" - }, - "name": "SDWebImageDownloaderHighPriority", - "visibility": "public" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFUmPjp9CtnN2Y=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "MKAnnotationView (WebCache)", - "visibility": "public", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPndIiv0KoI=", - "_parent": { - "$ref": "AAAAAAFUmPjp9CtnN2Y=" - }, - "name": "sd_setImageWithURL", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFUmPoFSiy4ZTk=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "UIButton (WebCache)", - "visibility": "public", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPsYkS1rEno=", - "_parent": { - "$ref": "AAAAAAFUmPoFSiy4ZTk=" - }, - "name": "sd_setImageWithURL", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFUmPtmMC6BqlU=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "UIImageView (WebCache)", - "visibility": "public", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFUmPuK4C6yWrI=", - "_parent": { - "$ref": "AAAAAAFUmPtmMC6BqlU=" - }, - "name": "sd_setImageWithURL", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFXmnErIidawX8=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "UIImageView (HighlightedWebCache)", - "visibility": "public", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFXmnErIideM/I=", - "_parent": { - "$ref": "AAAAAAFXmnErIidawX8=" - }, - "name": "sd_setHighlightedImageWithURL", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFXmsqK3SdrXmw=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "UIView (WebCache)", - "ownedElements": [ - { - "_type": "UMLDependency", - "_id": "AAAAAAFXmtleW1rTTNk=", - "_parent": { - "$ref": "AAAAAAFXmsqK3SdrXmw=" - }, - "source": { - "$ref": "AAAAAAFUkh79WI34fB0=" - }, - "target": { - "$ref": "AAAAAAFXmwGn6ZeqpYw=" - }, - "visibility": "public" - }, - { - "_type": "UMLDependency", - "_id": "AAAAAAFXmuaszox/B8Y=", - "_parent": { - "$ref": "AAAAAAFXmsqK3SdrXmw=" - }, - "source": { - "$ref": "AAAAAAFXmsqK3SdrXmw=" - }, - "target": { - "$ref": "AAAAAAFUkhwuq42z3w4=" - }, - "visibility": "public" - } - ], - "visibility": "public", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFXmsqK3idvzv0=", - "_parent": { - "$ref": "AAAAAAFXmsqK3SdrXmw=" - }, - "name": "sd_internalSetImageWithURL", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFXmtV2dyd8ar4=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "FLAnimatedImageView (WebCache)", - "visibility": "public", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFXmtV2eCeAZR4=", - "_parent": { - "$ref": "AAAAAAFXmtV2dyd8ar4=" - }, - "name": "sd_setImageWithURL", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLInterface", - "_id": "AAAAAAFfKte+K96ya3s=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageCoder", - "ownedElements": [ - { - "_type": "UMLInterfaceRealization", - "_id": "AAAAAAFfKu3J8hGXH0g=", - "_parent": { - "$ref": "AAAAAAFfKte+K96ya3s=" - }, - "source": { - "$ref": "AAAAAAFfKukEJfyENXE=" - }, - "target": { - "$ref": "AAAAAAFfKte+K96ya3s=" - }, - "visibility": "public" - }, - { - "_type": "UMLInterfaceRealization", - "_id": "AAAAAAFfKu8vtRgLlUU=", - "_parent": { - "$ref": "AAAAAAFfKte+K96ya3s=" - }, - "source": { - "$ref": "AAAAAAFfKumijf36cE8=" - }, - "target": { - "$ref": "AAAAAAFfKte+K96ya3s=" - }, - "visibility": "public" - } - ], - "visibility": "public", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFfKtg9W998WOc=", - "_parent": { - "$ref": "AAAAAAFfKte+K96ya3s=" - }, - "name": "canDecode", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKtmVHeA1m00=", - "_parent": { - "$ref": "AAAAAAFfKtg9W998WOc=" - }, - "name": "Parameter1", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "BOOL", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "return" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKt/Vs+e/T58=", - "_parent": { - "$ref": "AAAAAAFfKtg9W998WOc=" - }, - "name": "data", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFfKtrKNePvsF8=", - "_parent": { - "$ref": "AAAAAAFfKte+K96ya3s=" - }, - "name": "decodedImage", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKts3/uThE8I=", - "_parent": { - "$ref": "AAAAAAFfKtrKNePvsF8=" - }, - "name": "Parameter1", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "UIImage", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "return" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKuBV2+icmFY=", - "_parent": { - "$ref": "AAAAAAFfKtrKNePvsF8=" - }, - "name": "data", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFfKt9HI+ZOKlw=", - "_parent": { - "$ref": "AAAAAAFfKte+K96ya3s=" - }, - "name": "decompressedImage", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKuJ4lukwtrM=", - "_parent": { - "$ref": "AAAAAAFfKt9HI+ZOKlw=" - }, - "name": "image", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKuKdhunEK0Y=", - "_parent": { - "$ref": "AAAAAAFfKt9HI+ZOKlw=" - }, - "name": "data", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "inout" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKuMSpuqieQU=", - "_parent": { - "$ref": "AAAAAAFfKt9HI+ZOKlw=" - }, - "name": "options", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKuNut+s2QQU=", - "_parent": { - "$ref": "AAAAAAFfKt9HI+ZOKlw=" - }, - "name": "Parameter1", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "UIImage", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "return" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFfKuUPYO6usi8=", - "_parent": { - "$ref": "AAAAAAFfKte+K96ya3s=" - }, - "name": "canEncode", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKuVH0O9XDn4=", - "_parent": { - "$ref": "AAAAAAFfKuUPYO6usi8=" - }, - "name": "format", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKuVrIe/rxRg=", - "_parent": { - "$ref": "AAAAAAFfKuUPYO6usi8=" - }, - "name": "Parameter1", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "BOOL", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "return" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFfKuW6ofDJluc=", - "_parent": { - "$ref": "AAAAAAFfKte+K96ya3s=" - }, - "name": "encodedData", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKuXdAfFy850=", - "_parent": { - "$ref": "AAAAAAFfKuW6ofDJluc=" - }, - "name": "image", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKuYFWfIGIs0=", - "_parent": { - "$ref": "AAAAAAFfKuW6ofDJluc=" - }, - "name": "format", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKuYeevKaklM=", - "_parent": { - "$ref": "AAAAAAFfKuW6ofDJluc=" - }, - "name": "Parameter1", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "NSData", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "return" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false - }, - { - "_type": "UMLInterface", - "_id": "AAAAAAFfKuaHevMvVkQ=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageProgressiveCoder", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFfKutJugVRytg=", - "_parent": { - "$ref": "AAAAAAFfKuaHevMvVkQ=" - }, - "source": { - "$ref": "AAAAAAFfKuaHevMvVkQ=" - }, - "target": { - "$ref": "AAAAAAFfKte+K96ya3s=" - }, - "visibility": "public" - }, - { - "_type": "UMLInterfaceRealization", - "_id": "AAAAAAFfKu+znBqqvWQ=", - "_parent": { - "$ref": "AAAAAAFfKuaHevMvVkQ=" - }, - "source": { - "$ref": "AAAAAAFfKul3rf0/okM=" - }, - "target": { - "$ref": "AAAAAAFfKuaHevMvVkQ=" - }, - "visibility": "public" - }, - { - "_type": "UMLInterfaceRealization", - "_id": "AAAAAAFfKu/8NRxLVBY=", - "_parent": { - "$ref": "AAAAAAFfKuaHevMvVkQ=" - }, - "source": { - "$ref": "AAAAAAFfKunO1f612hU=" - }, - "target": { - "$ref": "AAAAAAFfKuaHevMvVkQ=" - }, - "visibility": "public" - } - ], - "visibility": "public", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFfKudnG/biyzM=", - "_parent": { - "$ref": "AAAAAAFfKuaHevMvVkQ=" - }, - "name": "canIncrementallyDecode", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKuexY/hArUE=", - "_parent": { - "$ref": "AAAAAAFfKudnG/biyzM=" - }, - "name": "data", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKufG4/jUFsY=", - "_parent": { - "$ref": "AAAAAAFfKudnG/biyzM=" - }, - "name": "Parameter1", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "BOOL", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "return" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFfKugU/PmNPJQ=", - "_parent": { - "$ref": "AAAAAAFfKuaHevMvVkQ=" - }, - "name": "incrementallyDecodedImage", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKuhBpPo2Nvo=", - "_parent": { - "$ref": "AAAAAAFfKugU/PmNPJQ=" - }, - "name": "data", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKuhgzPrKttY=", - "_parent": { - "$ref": "AAAAAAFfKugU/PmNPJQ=" - }, - "name": "finished", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKuiGTftezNo=", - "_parent": { - "$ref": "AAAAAAFfKugU/PmNPJQ=" - }, - "name": "Parameter1", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "UIImage", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "return" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFfKukEJfyENXE=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageCodersManager", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFfKvC15R9UsRU=", - "_parent": { - "$ref": "AAAAAAFfKukEJfyENXE=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFfKvC15h9VJ8U=", - "_parent": { - "$ref": "AAAAAAFfKvC15R9UsRU=" - }, - "reference": { - "$ref": "AAAAAAFfKumijf36cE8=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "none", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFfKvC15h9W5gU=", - "_parent": { - "$ref": "AAAAAAFfKvC15R9UsRU=" - }, - "reference": { - "$ref": "AAAAAAFfKukEJfyENXE=" - }, - "visibility": "public", - "navigable": true, - "aggregation": "composite", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "isID": false - }, - "visibility": "public", - "isDerived": false - } - ], - "visibility": "public", - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFfKvIMwCceZuI=", - "_parent": { - "$ref": "AAAAAAFfKukEJfyENXE=" - }, - "name": "sharedInstance", - "visibility": "public", - "isStatic": true, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFfKvJtjym0wQE=", - "_parent": { - "$ref": "AAAAAAFfKukEJfyENXE=" - }, - "name": "coders", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "NSArray ", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "isDerived": false, - "aggregation": "none", - "isID": false - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFfKvJK9yjW40I=", - "_parent": { - "$ref": "AAAAAAFfKukEJfyENXE=" - }, - "name": "add", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKvOdWTJKxZs=", - "_parent": { - "$ref": "AAAAAAFfKvJK9yjW40I=" - }, - "name": "coder", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFfKvPFeTMmARs=", - "_parent": { - "$ref": "AAAAAAFfKukEJfyENXE=" - }, - "name": "remove", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFfKvPZ+TQg+cs=", - "_parent": { - "$ref": "AAAAAAFfKvPFeTMmARs=" - }, - "name": "coder", - "visibility": "public", - "isStatic": false, - "isLeaf": false, - "type": "", - "isReadOnly": false, - "isOrdered": false, - "isUnique": false, - "direction": "in" - } - ], - "concurrency": "sequential", - "isQuery": false, - "isAbstract": false - } - ], - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFfKul3rf0/okM=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageImageIOCoder", - "visibility": "public", - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFfKumijf36cE8=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageGIFCoder", - "visibility": "public", - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFfKunO1f612hU=", - "_parent": { - "$ref": "AAAAAAFUkhbx4ozg49g=" - }, - "name": "SDWebImageWebPCoder", - "visibility": "public", - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - } - ], - "visibility": "public" - }, - { - "_type": "UMLPackage", - "_id": "AAAAAAFUkhchsIzka3U=", - "_parent": { - "$ref": "AAAAAAFF+qBWK6M3Z8Y=" - }, - "name": "WebP", - "visibility": "public" - }, - { - "_type": "UMLPackage", - "_id": "AAAAAAFUmOwkzAc9obg=", - "_parent": { - "$ref": "AAAAAAFF+qBWK6M3Z8Y=" - }, - "name": "Foundation", - "ownedElements": [ - { - "_type": "UMLClass", - "_id": "AAAAAAFUmOxnEwduTCw=", - "_parent": { - "$ref": "AAAAAAFUmOwkzAc9obg=" - }, - "name": "NSOperation", - "visibility": "public", - "isAbstract": false, - "isFinalSpecialization": false, - "isLeaf": false, - "isActive": false - } - ], - "visibility": "public" - } - ], - "visibility": "public" - } - ] -} diff --git a/Docs/SDWebImageClassDiagram.png b/Docs/SDWebImageClassDiagram.png deleted file mode 100644 index 1b0229874ee6f1b65c47597a75d3844b6014ba2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 345477 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Μ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%0A7tGY=mMkXt*J{xQ%f(?m445 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

A_JDWg;`9L#SJ-*JI*)70MDJ#R|vk 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 diff --git a/Docs/SDWebImageSequenceDiagram.png b/Docs/SDWebImageSequenceDiagram.png deleted file mode 100644 index fec907d0c88f3a7a2bedf4f8fb21f7b1aa3df848..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 131867 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 Min?-)qOteC0WH8#RsaA1 diff --git a/README.md b/README.md index 725ad2dc..0998de70 100644 --- a/README.md +++ b/README.md @@ -178,10 +178,28 @@ All source code is licensed under the [MIT License](https://raw.github.com/rs/SD ## Architecture +#### High Level Diagram

- +

+#### Overall Class Diagram

- +

+ +#### Top Level API Diagram +

+ +

+ +#### Main Sequence Diagram +

+ +

+ +#### More detailed diagrams +- [Manager API Diagram](Docs/Diagrams/SDWebImageManagerClassDiagram.png) +- [Coders API Diagram](Docs/Diagrams/SDWebImageCodersClassDiagram.png) +- [Loader API Diagram](Docs/Diagrams/SDWebImageLoaderClassDiagram.png) +- [Cache API Diagram](Docs/Diagrams/SDWebImageCacheClassDiagram.png) \ No newline at end of file From 217510e3469c46eca483a988a7d6a1a68128d0f8 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Tue, 31 Jul 2018 18:07:06 +0300 Subject: [PATCH 224/361] Bumped version to 5.0.0-beta2 --- CHANGELOG.md | 13 +++++++++++++ SDWebImage.podspec | 2 +- WebImage/Info.plist | 4 ++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8b94883..2604d83a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## [5.0.0-beta2 - Customizable SDWebImage, on Jul 31st, 2018](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta2) +See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/milestone/15) + +#### Features +- Add `SDImageCoderWebImageContext` coder option, which allow custom coder plugin, to receive the context option from top-level API #2405 +- Updated all existing diagrams for 5.0 release + added new ones (small detailed diagrams for the most important components) #2407 + +#### Fixes +- Fix nullable key for `sd_imageLoadOperationForKey` #2389 +- Replace `__bridge_transfer` with `__bridge` when convert from `CFStringRef` to `NSString` #2392 +- Rename `sd_UTTypeFromSDImageFormat` to `sd_UTTypeFromImageFormat` #2395 +- Change `SDImageFormat` to use `NS_TYPED_EXTENSIBLE_ENUM` instead of fixed enum, to allow custom coder plugins to extend it #2400 + ## [4.4.2 - 4.4 patch, on July 18th, 2018](https://github.com/rs/SDWebImage/releases/tag/4.4.2) See [all tickets marked for the 4.4.2 release](https://github.com/rs/SDWebImage/milestone/27) diff --git a/SDWebImage.podspec b/SDWebImage.podspec index 83cc57b2..cadc8034 100644 --- a/SDWebImage.podspec +++ b/SDWebImage.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'SDWebImage' - s.version = '5.0.0-beta' + s.version = '5.0.0-beta2' s.osx.deployment_target = '10.10' s.ios.deployment_target = '8.0' diff --git a/WebImage/Info.plist b/WebImage/Info.plist index 77696b33..20874b51 100644 --- a/WebImage/Info.plist +++ b/WebImage/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.0.0-beta + 5.0.0-beta2 CFBundleSignature ???? CFBundleVersion - 5.0.0-beta + 5.0.0-beta2 NSPrincipalClass From 03434c5a47c86b401d1f856f6e62f774ec9db63f Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Wed, 1 Aug 2018 12:26:28 +0300 Subject: [PATCH 225/361] Updated the diagrams: added to the Coders detail diagram the coders available in dedicated projects at github.com/SDWebImage: SDWebImageFLCoder, SDWebImagePhotosLoader, SDWebImageHEIFCoder, SDWebImageBPGCoder --- Docs/Diagrams/SDWebImage.mdj | 2562 ++++++++++++++--- .../Diagrams/SDWebImageCodersClassDiagram.png | Bin 113615 -> 142417 bytes 2 files changed, 2202 insertions(+), 360 deletions(-) diff --git a/Docs/Diagrams/SDWebImage.mdj b/Docs/Diagrams/SDWebImage.mdj index b26b7b17..b75ed9fe 100644 --- a/Docs/Diagrams/SDWebImage.mdj +++ b/Docs/Diagrams/SDWebImage.mdj @@ -1533,7 +1533,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 786, + "left": 791, "top": 237, "width": 62.36572265625, "height": 13, @@ -1568,7 +1568,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 831, + "left": 836, "top": 228, "width": 0, "height": 13, @@ -1602,7 +1602,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 876, + "left": 881, "top": 229, "width": 0, "height": 13, @@ -1738,7 +1738,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 846, + "left": 851, "top": 74, "width": 0, "height": 13, @@ -1772,7 +1772,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 832, + "left": 837, "top": 77, "width": 0, "height": 13, @@ -1806,7 +1806,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 873, + "left": 878, "top": 70, "width": 0, "height": 13, @@ -1887,7 +1887,7 @@ "$ref": "AAAAAAFUmMuDNcmaKIo=" }, "lineStyle": 0, - "points": "521:235;861:235;861:55", + "points": "521:235;866:235;866:55", "stereotypeDisplay": "none", "showVisibility": true, "showProperty": true, @@ -5125,7 +5125,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 488, + "left": 461, "top": 296, "width": 121.03076171875, "height": 13, @@ -5160,7 +5160,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 449, + "left": 422, "top": 297, "width": 0, "height": 13, @@ -5194,7 +5194,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 493, + "left": 466, "top": 298, "width": 0, "height": 13, @@ -5330,7 +5330,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 464, + "left": 437, "top": 274, "width": 0, "height": 13, @@ -5364,7 +5364,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 450, + "left": 423, "top": 277, "width": 0, "height": 13, @@ -5398,7 +5398,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 491, + "left": 464, "top": 270, "width": 0, "height": 13, @@ -5479,7 +5479,7 @@ "$ref": "AAAAAAFky2+2+WTD+rs=" }, "lineStyle": 0, - "points": "480:304;479:304;479:255", + "points": "480:304;452:304;452:255", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -7486,7 +7486,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 925, + "left": 932, "top": 228, "width": 0, "height": 13, @@ -7520,7 +7520,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 910, + "left": 917, "top": 228, "width": 0, "height": 13, @@ -7554,7 +7554,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 954, + "left": 961, "top": 229, "width": 0, "height": 13, @@ -7587,7 +7587,7 @@ "$ref": "AAAAAAFUmMuDNcmaKIo=" }, "lineStyle": 0, - "points": "521:235;940:235;940:175", + "points": "521:235;947:235;947:175", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -7629,7 +7629,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 1242, + "left": 1250, "top": 412, "width": 0, "height": 13, @@ -7663,7 +7663,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 1227, + "left": 1235, "top": 412, "width": 0, "height": 13, @@ -7697,7 +7697,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 1271, + "left": 1279, "top": 413, "width": 0, "height": 13, @@ -7730,7 +7730,7 @@ "$ref": "AAAAAAFUmNdyjto3Jy4=" }, "lineStyle": 0, - "points": "646:419;1257:419;1257:367", + "points": "646:419;1265:419;1265:367", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -8468,7 +8468,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 929, + "left": 935, "top": 412, "width": 0, "height": 13, @@ -8502,7 +8502,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 914, + "left": 920, "top": 412, "width": 0, "height": 13, @@ -8536,7 +8536,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 959, + "left": 965, "top": 413, "width": 0, "height": 13, @@ -8569,7 +8569,7 @@ "$ref": "AAAAAAFUmNdyjto3Jy4=" }, "lineStyle": 0, - "points": "646:419;944:419;944:303", + "points": "646:419;950:419;950:303", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -12220,7 +12220,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 736, + "left": 740, "top": 787, "width": 0, "height": 13, @@ -12254,7 +12254,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 736, + "left": 740, "top": 772, "width": 0, "height": 13, @@ -12288,7 +12288,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 736, + "left": 740, "top": 817, "width": 0, "height": 13, @@ -12321,7 +12321,7 @@ "$ref": "AAAAAAFfKucZUPTSZzA=" }, "lineStyle": 0, - "points": "689:856;689:808;784:808;784:772", + "points": "693:856;693:808;787:808;787:772", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -12363,7 +12363,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 452, + "left": 456, "top": 459, "width": 0, "height": 13, @@ -12397,7 +12397,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 452, + "left": 456, "top": 444, "width": 0, "height": 13, @@ -12431,7 +12431,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 452, + "left": 456, "top": 489, "width": 0, "height": 13, @@ -12464,7 +12464,7 @@ "$ref": "AAAAAAFUmNdXmNnpp1I=" }, "lineStyle": 0, - "points": "359:439;359:480;545:480;545:728", + "points": "362:439;362:480;550:480;550:728", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -12792,8 +12792,8 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 839, - "top": 861, + "left": 875, + "top": 949, "width": 0, "height": 13, "autoResize": false, @@ -12826,8 +12826,8 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 839, - "top": 846, + "left": 860, + "top": 949, "width": 0, "height": 13, "autoResize": false, @@ -12860,8 +12860,8 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 839, - "top": 891, + "left": 904, + "top": 950, "width": 0, "height": 13, "autoResize": false, @@ -12893,7 +12893,7 @@ "$ref": "AAAAAAFfKumzBf41WYU=" }, "lineStyle": 0, - "points": "839:1005;839:882;840:882", + "points": "890:1005;890:908", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -14934,7 +14934,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 859, + "left": 863, "top": 817, "width": 0, "height": 13, @@ -14968,7 +14968,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 859, + "left": 863, "top": 832, "width": 0, "height": 13, @@ -15002,7 +15002,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 860, + "left": 864, "top": 787, "width": 0, "height": 13, @@ -15035,7 +15035,7 @@ "$ref": "AAAAAAFky0klQadyygU=" }, "lineStyle": 0, - "points": "937:856;937:808;784:808;784:772", + "points": "942:856;942:808;787:808;787:772", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -15220,7 +15220,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 787, + "left": 790, "top": 977, "width": 0, "height": 13, @@ -15254,7 +15254,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 787, + "left": 790, "top": 992, "width": 0, "height": 13, @@ -15288,7 +15288,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 788, + "left": 791, "top": 947, "width": 0, "height": 13, @@ -15321,7 +15321,7 @@ "$ref": "AAAAAAFfKumzBf41WYU=" }, "lineStyle": 0, - "points": "887:1005;887:968;689:968;689:908", + "points": "890:1005;890:968;693:968;693:908", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -15363,7 +15363,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 843, + "left": 846, "top": 963, "width": 0, "height": 13, @@ -15397,7 +15397,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 843, + "left": 846, "top": 948, "width": 0, "height": 13, @@ -15431,7 +15431,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 843, + "left": 846, "top": 993, "width": 0, "height": 13, @@ -15464,7 +15464,7 @@ "$ref": "AAAAAAFfKunfeP7w4nM=" }, "lineStyle": 0, - "points": "749:1005;749:984;937:984;937:908", + "points": "751:1005;751:984;942:984;942:908", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -15794,7 +15794,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 858, + "left": 861, "top": 961, "width": 0, "height": 13, @@ -15828,7 +15828,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 858, + "left": 861, "top": 976, "width": 0, "height": 13, @@ -15862,7 +15862,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 859, + "left": 862, "top": 931, "width": 0, "height": 13, @@ -15895,7 +15895,7 @@ "$ref": "AAAAAAFky08/ucTKxlE=" }, "lineStyle": 0, - "points": "1029:1005;1029:952;689:952;689:908", + "points": "1032:1005;1032:952;693:952;693:908", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -17706,7 +17706,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 1182, + "left": 1187, "top": 276, "width": 0, "height": 13, @@ -17740,7 +17740,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 1167, + "left": 1172, "top": 276, "width": 0, "height": 13, @@ -17774,7 +17774,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 1212, + "left": 1217, "top": 277, "width": 0, "height": 13, @@ -17807,7 +17807,7 @@ "$ref": "AAAAAAFXmuWYrYcCa9s=" }, "lineStyle": 0, - "points": "1040:283;1197:283;1197:180", + "points": "1040:283;1202:283;1202:180", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -19531,7 +19531,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 701, + "left": 711, "top": 592, "width": 0, "height": 13, @@ -19565,7 +19565,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 701, + "left": 711, "top": 577, "width": 0, "height": 13, @@ -19599,7 +19599,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 701, + "left": 711, "top": 622, "width": 0, "height": 13, @@ -19632,7 +19632,7 @@ "$ref": "AAAAAAFky5X9gfXo5U4=" }, "lineStyle": 0, - "points": "701:632;701:613;702:613;702:588", + "points": "711:632;711:613;712:613;712:588", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -22007,7 +22007,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 563, + "left": 568, "top": 501, "width": 0, "height": 13, @@ -22041,7 +22041,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 563, + "left": 568, "top": 486, "width": 0, "height": 13, @@ -22075,7 +22075,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 563, + "left": 568, "top": 531, "width": 0, "height": 13, @@ -22108,7 +22108,7 @@ "$ref": "AAAAAAFUmNdyjto3Jy4=" }, "lineStyle": 0, - "points": "563:439;563:522;872:522", + "points": "568:439;568:522;872:522", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -25726,7 +25726,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 91, + "left": 97, "top": 102, "width": 0, "height": 13, @@ -25760,7 +25760,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 91, + "left": 97, "top": 87, "width": 0, "height": 13, @@ -25794,7 +25794,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 91, + "left": 97, "top": 132, "width": 0, "height": 13, @@ -25827,7 +25827,7 @@ "$ref": "AAAAAAFUmPubFi7kzSY=" }, "lineStyle": 0, - "points": "91:55;91:123;360:123", + "points": "97:55;97:123;360:123", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -25869,7 +25869,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 493, + "left": 497, "top": 132, "width": 0, "height": 13, @@ -25903,7 +25903,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 493, + "left": 497, "top": 147, "width": 0, "height": 13, @@ -25937,7 +25937,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 494, + "left": 498, "top": 102, "width": 0, "height": 13, @@ -25970,7 +25970,7 @@ "$ref": "AAAAAAFUmPsPJi0J5Fw=" }, "lineStyle": 0, - "points": "494:55;494:123;489:123", + "points": "498:55;498:123;489:123", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -26012,7 +26012,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 669, + "left": 676, "top": 132, "width": 0, "height": 13, @@ -26046,7 +26046,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 669, + "left": 676, "top": 147, "width": 0, "height": 13, @@ -26080,7 +26080,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 670, + "left": 677, "top": 102, "width": 0, "height": 13, @@ -26113,7 +26113,7 @@ "$ref": "AAAAAAFUmPnxoSwmlwM=" }, "lineStyle": 0, - "points": "670:55;670:123;489:123", + "points": "677:55;677:123;489:123", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -26155,8 +26155,8 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 92, - "top": 136, + "left": 96, + "top": 116, "width": 0, "height": 13, "autoResize": false, @@ -26189,8 +26189,8 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 107, - "top": 136, + "left": 111, + "top": 116, "width": 0, "height": 13, "autoResize": false, @@ -26223,8 +26223,8 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 63, - "top": 137, + "left": 67, + "top": 117, "width": 0, "height": 13, "autoResize": false, @@ -26256,7 +26256,7 @@ "$ref": "AAAAAAFXmsqnFRq0kTA=" }, "lineStyle": 0, - "points": "360:143;78:143;78:144", + "points": "360:123;82:123;82:144", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -26441,7 +26441,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 447, + "left": 451, "top": 179, "width": 0, "height": 13, @@ -26475,7 +26475,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 447, + "left": 451, "top": 194, "width": 0, "height": 13, @@ -26509,7 +26509,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 448, + "left": 452, "top": 149, "width": 0, "height": 13, @@ -26542,7 +26542,7 @@ "$ref": "AAAAAAFUmMuDNcmaKIo=" }, "lineStyle": 0, - "points": "448:216;448:170;149:170", + "points": "452:216;452:170;149:170", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -26992,7 +26992,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 1003, + "left": 1008, "top": 339, "width": 0, "height": 13, @@ -27026,7 +27026,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 1003, + "left": 1008, "top": 354, "width": 0, "height": 13, @@ -27060,7 +27060,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 1004, + "left": 1009, "top": 309, "width": 0, "height": 13, @@ -27093,7 +27093,7 @@ "$ref": "AAAAAAFk7AANcUb769w=" }, "lineStyle": 0, - "points": "1004:368;1004:330;641:330", + "points": "1009:368;1009:330;641:330", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -27688,7 +27688,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 89, + "left": 94, "top": 309, "width": 0, "height": 13, @@ -27722,7 +27722,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 89, + "left": 94, "top": 294, "width": 0, "height": 13, @@ -27756,7 +27756,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 89, + "left": 94, "top": 339, "width": 0, "height": 13, @@ -27789,7 +27789,7 @@ "$ref": "AAAAAAFk7AJFfl1wqqg=" }, "lineStyle": 0, - "points": "89:400;89:330;288:330", + "points": "94:400;94:330;288:330", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -30094,7 +30094,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 217, + "left": 221, "top": 981, "width": 0, "height": 13, @@ -30128,7 +30128,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 217, + "left": 221, "top": 996, "width": 0, "height": 13, @@ -30162,7 +30162,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 218, + "left": 222, "top": 951, "width": 0, "height": 13, @@ -30195,7 +30195,7 @@ "$ref": "AAAAAAFk7BOaWPrCtDM=" }, "lineStyle": 0, - "points": "304:973;304:972;133:972;133:973", + "points": "304:973;304:972;140:972;140:973", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -34004,7 +34004,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 299, + "left": 307, "top": 102, "width": 0, "height": 13, @@ -34038,7 +34038,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 299, + "left": 307, "top": 87, "width": 0, "height": 13, @@ -34072,7 +34072,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 299, + "left": 307, "top": 132, "width": 0, "height": 13, @@ -34105,7 +34105,7 @@ "$ref": "AAAAAAFk7CarUIbnZao=" }, "lineStyle": 0, - "points": "299:55;299:123;360:123", + "points": "307:55;307:123;360:123", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -38620,7 +38620,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 736, + "left": 741, "top": 1161, "width": 0, "height": 13, @@ -38654,7 +38654,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 736, + "left": 741, "top": 1176, "width": 0, "height": 13, @@ -38688,7 +38688,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 737, + "left": 742, "top": 1131, "width": 0, "height": 13, @@ -38721,7 +38721,7 @@ "$ref": "AAAAAAFk7D6tiK11uE8=" }, "lineStyle": 0, - "points": "840:1168;840:1152;634:1152;634:1108", + "points": "846:1168;846:1152;638:1152;638:1108", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -41143,9 +41143,9 @@ "containerChangeable": false, "containerExtending": false, "left": 736, - "top": 246, + "top": 240, "width": 213, - "height": 26, + "height": 39, "autoResize": false, "alpha": -3.2532755257807673, "distance": 107.67079455451233, @@ -52032,11 +52032,129 @@ }, { "_type": "UMLPackage", - "_id": "AAAAAAFUkhchsIzka3U=", + "_id": "AAAAAAFk9MO/s6f28O8=", "_parent": { "$ref": "AAAAAAFF+qBWK6M3Z8Y=" }, - "name": "WebP", + "name": "SDWebImage-external", + "ownedElements": [ + { + "_type": "UMLClass", + "_id": "AAAAAAFk9MRfHagAcBw=", + "_parent": { + "$ref": "AAAAAAFk9MO/s6f28O8=" + }, + "name": "SDWebImageFLCoder", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk9MpUR6lBM+g=", + "_parent": { + "$ref": "AAAAAAFk9MRfHagAcBw=" + }, + "source": { + "$ref": "AAAAAAFk9MRfHagAcBw=" + }, + "target": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk9MSxhqgEZag=", + "_parent": { + "$ref": "AAAAAAFk9MO/s6f28O8=" + }, + "name": "SDWebImageBPGCoder", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk9MqCl6l0L/Q=", + "_parent": { + "$ref": "AAAAAAFk9MSxhqgEZag=" + }, + "source": { + "$ref": "AAAAAAFk9MSxhqgEZag=" + }, + "target": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk9MToV6gIYTs=", + "_parent": { + "$ref": "AAAAAAFk9MO/s6f28O8=" + }, + "name": "SDWebImageHEIFCoder", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk9MpyLaljD/M=", + "_parent": { + "$ref": "AAAAAAFk9MToV6gIYTs=" + }, + "source": { + "$ref": "AAAAAAFk9MToV6gIYTs=" + }, + "target": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + }, + { + "_type": "UMLClass", + "_id": "AAAAAAFk9Mbgf6gMd5c=", + "_parent": { + "$ref": "AAAAAAFk9MO/s6f28O8=" + }, + "name": "SDWebImagePhotosLoader", + "ownedElements": [ + { + "_type": "UMLInterfaceRealization", + "_id": "AAAAAAFk9MpmRalSMfM=", + "_parent": { + "$ref": "AAAAAAFk9Mbgf6gMd5c=" + }, + "source": { + "$ref": "AAAAAAFk9Mbgf6gMd5c=" + }, + "target": { + "$ref": "AAAAAAFfKte+K96ya3s=" + }, + "visibility": "public" + } + ], + "visibility": "public", + "isAbstract": false, + "isFinalSpecialization": false, + "isLeaf": false, + "isActive": false + } + ], "visibility": "public" }, { @@ -52404,7 +52522,7 @@ "containerExtending": false, "left": 456, "top": 242, - "width": 196, + "width": 204.84130859375, "height": 23, "autoResize": false }, @@ -52632,7 +52750,7 @@ "containerExtending": false, "left": 192, "top": 16, - "width": 240, + "width": 258.197265625, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -53094,7 +53212,7 @@ "containerExtending": false, "left": 16, "top": 16, - "width": 168, + "width": 179.64501953125, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -53556,7 +53674,7 @@ "containerExtending": false, "left": 440, "top": 16, - "width": 232, + "width": 247.583984375, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -54018,7 +54136,7 @@ "containerExtending": false, "left": 680, "top": 16, - "width": 205, + "width": 220.23828125, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -54571,7 +54689,7 @@ "containerExtending": false, "left": 896, "top": 66, - "width": 152, + "width": 156.2119140625, "height": 23, "autoResize": false }, @@ -55067,7 +55185,7 @@ "containerExtending": false, "left": 1064, "top": 56, - "width": 266, + "width": 278.7978515625, "height": 53, "autoResize": false }, @@ -55849,7 +55967,7 @@ "containerExtending": false, "left": 288, "top": 534, - "width": 519, + "width": 556.36181640625, "height": 68, "autoResize": false }, @@ -56642,7 +56760,7 @@ "containerExtending": false, "left": 16, "top": 376, - "width": 209, + "width": 213.06787109375, "height": 53, "autoResize": false, "stereotypeLabel": { @@ -57412,7 +57530,7 @@ "containerExtending": false, "left": 1392, "top": 24, - "width": 219, + "width": 224.10009765625, "height": 53, "autoResize": false, "stereotypeLabel": { @@ -58664,7 +58782,7 @@ "containerExtending": false, "left": 16, "top": 165, - "width": 168, + "width": 176.333984375, "height": 188, "autoResize": false } @@ -59616,7 +59734,7 @@ "containerExtending": false, "left": 416, "top": 214, - "width": 519, + "width": 556.36181640625, "height": 68, "autoResize": false }, @@ -59845,7 +59963,7 @@ "containerExtending": false, "left": 96, "top": 16, - "width": 209, + "width": 213.06787109375, "height": 53, "autoResize": false, "stereotypeLabel": { @@ -60822,7 +60940,7 @@ "containerExtending": false, "left": 192, "top": 397, - "width": 464, + "width": 491.42529296875, "height": 83, "autoResize": false }, @@ -61171,7 +61289,7 @@ "containerExtending": false, "left": 664, "top": 397, - "width": 537, + "width": 569.43798828125, "height": 38, "autoResize": false }, @@ -62482,7 +62600,7 @@ "containerExtending": false, "left": 16, "top": 584, - "width": 210, + "width": 210.82080078125, "height": 113, "autoResize": false }, @@ -63726,7 +63844,7 @@ "containerExtending": false, "left": 232, "top": 652, - "width": 424, + "width": 449.60693359375, "height": 323, "autoResize": false }, @@ -64509,7 +64627,7 @@ "containerExtending": false, "left": 664, "top": 682, - "width": 523, + "width": 561.32568359375, "height": 98, "autoResize": false }, @@ -64976,7 +65094,7 @@ "containerExtending": false, "left": 1192, "top": 584, - "width": 212, + "width": 219.37744140625, "height": 38, "autoResize": false }, @@ -65432,7 +65550,7 @@ "containerExtending": false, "left": 1040, "top": 32, - "width": 228, + "width": 232.66943359375, "height": 53, "autoResize": false, "stereotypeLabel": { @@ -65552,7 +65670,7 @@ "containerExtending": false, "left": 1040, "top": 85, - "width": 252, + "width": 266.4833984375, "height": 38, "autoResize": false }, @@ -65847,7 +65965,7 @@ "containerExtending": false, "left": 1392, "top": 72, - "width": 274, + "width": 289.90625, "height": 23, "autoResize": false }, @@ -67106,7 +67224,7 @@ "containerExtending": false, "left": 1040, "top": 197, - "width": 259, + "width": 267.78466796875, "height": 23, "autoResize": false }, @@ -68176,7 +68294,7 @@ "containerExtending": false, "left": 1392, "top": 232, - "width": 186, + "width": 195.58642578125, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -68638,7 +68756,7 @@ "containerExtending": false, "left": 1392, "top": 144, - "width": 190, + "width": 198.931640625, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -69583,7 +69701,7 @@ "containerExtending": false, "left": 8, "top": 189, - "width": 168, + "width": 176.333984375, "height": 188, "autoResize": false } @@ -69850,7 +69968,7 @@ "containerExtending": false, "left": 21, "top": 23, - "width": 194, + "width": 199.98291015625, "height": 13, "autoResize": false, "underline": false, @@ -69876,7 +69994,7 @@ "containerExtending": false, "left": 21, "top": 38, - "width": 194, + "width": 199.98291015625, "height": 13, "autoResize": false, "underline": false, @@ -69922,7 +70040,7 @@ "containerExtending": false, "left": 16, "top": 16, - "width": 204, + "width": 209.98291015625, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -69968,7 +70086,7 @@ "containerExtending": false, "left": 21, "top": 61, - "width": 194, + "width": 199.98291015625, "height": 13, "autoResize": false, "underline": true, @@ -69997,7 +70115,7 @@ "containerExtending": false, "left": 21, "top": 76, - "width": 194, + "width": 199.98291015625, "height": 13, "autoResize": false, "underline": false, @@ -70018,7 +70136,7 @@ "containerExtending": false, "left": 16, "top": 56, - "width": 204, + "width": 209.98291015625, "height": 38, "autoResize": false }, @@ -70052,7 +70170,7 @@ "containerExtending": false, "left": 21, "top": 99, - "width": 194, + "width": 199.98291015625, "height": 13, "autoResize": false, "underline": false, @@ -70081,7 +70199,7 @@ "containerExtending": false, "left": 21, "top": 114, - "width": 194, + "width": 199.98291015625, "height": 13, "autoResize": false, "underline": false, @@ -70102,7 +70220,7 @@ "containerExtending": false, "left": 16, "top": 94, - "width": 204, + "width": 209.98291015625, "height": 38, "autoResize": false }, @@ -70166,7 +70284,7 @@ "containerExtending": false, "left": 16, "top": 16, - "width": 204, + "width": 209.98291015625, "height": 116, "autoResize": false, "stereotypeDisplay": "label", @@ -70233,7 +70351,7 @@ "containerExtending": false, "left": 317, "top": 21, - "width": 233, + "width": 251.28515625, "height": 13, "autoResize": false, "underline": false, @@ -70259,7 +70377,7 @@ "containerExtending": false, "left": 317, "top": 36, - "width": 233, + "width": 251.28515625, "height": 13, "autoResize": false, "underline": false, @@ -70285,7 +70403,7 @@ "containerExtending": false, "left": 317, "top": 51, - "width": 233, + "width": 251.28515625, "height": 13, "autoResize": false, "underline": false, @@ -70331,7 +70449,7 @@ "containerExtending": false, "left": 312, "top": 16, - "width": 243, + "width": 261.28515625, "height": 53, "autoResize": false, "stereotypeLabel": { @@ -70401,7 +70519,7 @@ "containerExtending": false, "left": 317, "top": 74, - "width": 257, + "width": 275.28515625, "height": 13, "autoResize": false, "underline": false, @@ -70430,7 +70548,7 @@ "containerExtending": false, "left": 317, "top": 89, - "width": 257, + "width": 275.28515625, "height": 13, "autoResize": false, "underline": false, @@ -70459,7 +70577,7 @@ "containerExtending": false, "left": 317, "top": 104, - "width": 257, + "width": 275.28515625, "height": 13, "autoResize": false, "underline": false, @@ -70488,7 +70606,7 @@ "containerExtending": false, "left": 317, "top": 119, - "width": 257, + "width": 275.28515625, "height": 13, "autoResize": false, "underline": false, @@ -70509,7 +70627,7 @@ "containerExtending": false, "left": 312, "top": 69, - "width": 267, + "width": 285.28515625, "height": 68, "autoResize": false }, @@ -70573,7 +70691,7 @@ "containerExtending": false, "left": 312, "top": 16, - "width": 267, + "width": 285.28515625, "height": 132, "autoResize": false, "stereotypeDisplay": "decoration-label", @@ -70631,7 +70749,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 265, + "left": 268, "top": 85, "width": 0, "height": 13, @@ -70665,7 +70783,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 265, + "left": 268, "top": 70, "width": 0, "height": 13, @@ -70699,7 +70817,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 265, + "left": 268, "top": 115, "width": 0, "height": 13, @@ -70732,7 +70850,7 @@ "$ref": "AAAAAAFk73vslFKgg7c=" }, "lineStyle": 0, - "points": "219:106;312:106", + "points": "225:106;312:106", "stereotypeDisplay": "decoration-label", "showVisibility": true, "showProperty": true, @@ -70781,9 +70899,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 597, + "left": 613, "top": 21, - "width": 159, + "width": 172.8212890625, "height": 13, "autoResize": false, "underline": false, @@ -70807,9 +70925,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 597, + "left": 613, "top": 36, - "width": 159, + "width": 172.8212890625, "height": 13, "autoResize": false, "underline": false, @@ -70833,9 +70951,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 597, + "left": 613, "top": 51, - "width": 159, + "width": 172.8212890625, "height": 13, "autoResize": false, "underline": false, @@ -70859,7 +70977,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": -702, + "left": -670, "top": -112, "width": 0, "height": 13, @@ -70879,9 +70997,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 592, + "left": 608, "top": 16, - "width": 169, + "width": 182.8212890625, "height": 53, "autoResize": false, "stereotypeLabel": { @@ -70915,7 +71033,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": -351, + "left": -335, "top": -56, "width": 10, "height": 10, @@ -70939,7 +71057,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": -351, + "left": -335, "top": -56, "width": 10, "height": 10, @@ -70963,7 +71081,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": -351, + "left": -335, "top": -56, "width": 10, "height": 10, @@ -70987,7 +71105,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": -351, + "left": -335, "top": -56, "width": 10, "height": 10, @@ -71021,9 +71139,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 597, + "left": 613, "top": 74, - "width": 159, + "width": 172.8212890625, "height": 13, "autoResize": false, "underline": false, @@ -71050,9 +71168,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 597, + "left": 613, "top": 89, - "width": 159, + "width": 172.8212890625, "height": 13, "autoResize": false, "underline": false, @@ -71079,9 +71197,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 597, + "left": 613, "top": 104, - "width": 159, + "width": 172.8212890625, "height": 13, "autoResize": false, "underline": false, @@ -71108,9 +71226,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 597, + "left": 613, "top": 119, - "width": 159, + "width": 172.8212890625, "height": 13, "autoResize": false, "underline": false, @@ -71129,9 +71247,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 592, + "left": 608, "top": 69, - "width": 169, + "width": 182.8212890625, "height": 68, "autoResize": false } @@ -71145,9 +71263,9 @@ "showShadow": true, "containerChangeable": true, "containerExtending": false, - "left": 592, + "left": 608, "top": 16, - "width": 169, + "width": 182.8212890625, "height": 121, "autoResize": false, "stereotypeDisplay": "label", @@ -71218,7 +71336,7 @@ "containerExtending": false, "left": 21, "top": 197, - "width": 245, + "width": 265.21826171875, "height": 13, "autoResize": false, "underline": false, @@ -71244,7 +71362,7 @@ "containerExtending": false, "left": 21, "top": 212, - "width": 245, + "width": 265.21826171875, "height": 13, "autoResize": false, "underline": false, @@ -71270,7 +71388,7 @@ "containerExtending": false, "left": 21, "top": 227, - "width": 245, + "width": 265.21826171875, "height": 13, "autoResize": false, "underline": false, @@ -71316,7 +71434,7 @@ "containerExtending": false, "left": 16, "top": 192, - "width": 255, + "width": 275.21826171875, "height": 53, "autoResize": false, "stereotypeLabel": { @@ -71386,7 +71504,7 @@ "containerExtending": false, "left": 21, "top": 250, - "width": 269, + "width": 289.21826171875, "height": 13, "autoResize": false, "underline": false, @@ -71415,7 +71533,7 @@ "containerExtending": false, "left": 21, "top": 265, - "width": 269, + "width": 289.21826171875, "height": 13, "autoResize": false, "underline": false, @@ -71444,7 +71562,7 @@ "containerExtending": false, "left": 21, "top": 280, - "width": 269, + "width": 289.21826171875, "height": 13, "autoResize": false, "underline": false, @@ -71473,7 +71591,7 @@ "containerExtending": false, "left": 21, "top": 295, - "width": 269, + "width": 289.21826171875, "height": 13, "autoResize": false, "underline": false, @@ -71494,7 +71612,7 @@ "containerExtending": false, "left": 16, "top": 245, - "width": 279, + "width": 299.21826171875, "height": 68, "autoResize": false }, @@ -71558,7 +71676,7 @@ "containerExtending": false, "left": 16, "top": 192, - "width": 279, + "width": 299.21826171875, "height": 132, "autoResize": false, "stereotypeDisplay": "decoration-label", @@ -71625,7 +71743,7 @@ "containerExtending": false, "left": 325, "top": 197, - "width": 162, + "width": 172.27783203125, "height": 13, "autoResize": false, "underline": false, @@ -71651,7 +71769,7 @@ "containerExtending": false, "left": 325, "top": 212, - "width": 162, + "width": 172.27783203125, "height": 13, "autoResize": false, "underline": false, @@ -71677,7 +71795,7 @@ "containerExtending": false, "left": 325, "top": 227, - "width": 162, + "width": 172.27783203125, "height": 13, "autoResize": false, "underline": false, @@ -71723,7 +71841,7 @@ "containerExtending": false, "left": 320, "top": 192, - "width": 172, + "width": 182.27783203125, "height": 53, "autoResize": false, "stereotypeLabel": { @@ -71793,7 +71911,7 @@ "containerExtending": false, "left": 325, "top": 250, - "width": 186, + "width": 196.27783203125, "height": 13, "autoResize": false, "underline": false, @@ -71814,7 +71932,7 @@ "containerExtending": false, "left": 320, "top": 245, - "width": 196, + "width": 206.27783203125, "height": 23, "autoResize": false }, @@ -71878,7 +71996,7 @@ "containerExtending": false, "left": 320, "top": 192, - "width": 196, + "width": 206.27783203125, "height": 87, "autoResize": false, "stereotypeDisplay": "decoration-label", @@ -71943,9 +72061,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 565, - "top": 197, - "width": 206, + "left": 853, + "top": 253, + "width": 220.9052734375, "height": 13, "autoResize": false, "underline": false, @@ -71969,9 +72087,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 565, - "top": 212, - "width": 206, + "left": 853, + "top": 268, + "width": 220.9052734375, "height": 13, "autoResize": false, "underline": false, @@ -71995,9 +72113,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 565, - "top": 227, - "width": 206, + "left": 853, + "top": 283, + "width": 220.9052734375, "height": 13, "autoResize": false, "underline": false, @@ -72021,8 +72139,8 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": -874, - "top": -236, + "left": -298, + "top": -124, "width": 0, "height": 13, "autoResize": false, @@ -72041,9 +72159,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 560, - "top": 192, - "width": 216, + "left": 848, + "top": 248, + "width": 230.9052734375, "height": 53, "autoResize": false, "stereotypeLabel": { @@ -72077,8 +72195,8 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": -437, - "top": -118, + "left": -149, + "top": -62, "width": 10, "height": 10, "autoResize": false @@ -72111,9 +72229,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 565, - "top": 250, - "width": 230, + "left": 853, + "top": 306, + "width": 244.9052734375, "height": 13, "autoResize": false, "underline": false, @@ -72140,9 +72258,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 565, - "top": 265, - "width": 230, + "left": 853, + "top": 321, + "width": 244.9052734375, "height": 13, "autoResize": false, "underline": false, @@ -72169,9 +72287,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 565, - "top": 280, - "width": 230, + "left": 853, + "top": 336, + "width": 244.9052734375, "height": 13, "autoResize": false, "underline": false, @@ -72198,9 +72316,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 565, - "top": 295, - "width": 230, + "left": 853, + "top": 351, + "width": 244.9052734375, "height": 13, "autoResize": false, "underline": false, @@ -72227,9 +72345,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 565, - "top": 310, - "width": 230, + "left": 853, + "top": 366, + "width": 244.9052734375, "height": 13, "autoResize": false, "underline": false, @@ -72248,9 +72366,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 560, - "top": 245, - "width": 240, + "left": 848, + "top": 301, + "width": 254.9052734375, "height": 83, "autoResize": false }, @@ -72272,8 +72390,8 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": -437, - "top": -118, + "left": -149, + "top": -62, "width": 10, "height": 10, "autoResize": false @@ -72296,8 +72414,8 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": -437, - "top": -118, + "left": -149, + "top": -62, "width": 10, "height": 10, "autoResize": false @@ -72312,9 +72430,9 @@ "showShadow": true, "containerChangeable": true, "containerExtending": false, - "left": 560, - "top": 192, - "width": 240, + "left": 848, + "top": 248, + "width": 254.9052734375, "height": 147, "autoResize": false, "stereotypeDisplay": "decoration-label", @@ -72406,7 +72524,7 @@ "containerExtending": false, "left": 21, "top": 439, - "width": 118, + "width": 123.82373046875, "height": 13, "autoResize": false, "underline": false, @@ -72432,7 +72550,7 @@ "containerExtending": false, "left": 21, "top": 454, - "width": 118, + "width": 123.82373046875, "height": 13, "autoResize": false, "underline": false, @@ -72478,7 +72596,7 @@ "containerExtending": false, "left": 16, "top": 432, - "width": 128, + "width": 133.82373046875, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -72514,7 +72632,7 @@ "containerExtending": false, "left": 16, "top": 472, - "width": 128, + "width": 133.82373046875, "height": 10, "autoResize": false }, @@ -72538,7 +72656,7 @@ "containerExtending": false, "left": 16, "top": 482, - "width": 128, + "width": 133.82373046875, "height": 10, "autoResize": false }, @@ -72602,7 +72720,7 @@ "containerExtending": false, "left": 16, "top": 432, - "width": 128, + "width": 133.82373046875, "height": 60, "autoResize": false, "stereotypeDisplay": "label", @@ -72837,7 +72955,7 @@ "containerExtending": false, "left": 157, "top": 439, - "width": 129, + "width": 134.14501953125, "height": 13, "autoResize": false, "underline": false, @@ -72863,7 +72981,7 @@ "containerExtending": false, "left": 157, "top": 454, - "width": 129, + "width": 134.14501953125, "height": 13, "autoResize": false, "underline": false, @@ -72909,7 +73027,7 @@ "containerExtending": false, "left": 152, "top": 432, - "width": 139, + "width": 144.14501953125, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -72945,7 +73063,7 @@ "containerExtending": false, "left": 152, "top": 472, - "width": 139, + "width": 144.14501953125, "height": 10, "autoResize": false }, @@ -72969,7 +73087,7 @@ "containerExtending": false, "left": 152, "top": 482, - "width": 139, + "width": 144.14501953125, "height": 10, "autoResize": false }, @@ -73033,7 +73151,7 @@ "containerExtending": false, "left": 152, "top": 432, - "width": 139, + "width": 144.14501953125, "height": 60, "autoResize": false, "stereotypeDisplay": "label", @@ -73125,7 +73243,7 @@ "containerExtending": false, "left": 309, "top": 439, - "width": 118, + "width": 123.82373046875, "height": 13, "autoResize": false, "underline": false, @@ -73151,7 +73269,7 @@ "containerExtending": false, "left": 309, "top": 454, - "width": 118, + "width": 123.82373046875, "height": 13, "autoResize": false, "underline": false, @@ -73197,7 +73315,7 @@ "containerExtending": false, "left": 304, "top": 432, - "width": 128, + "width": 133.82373046875, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -73233,7 +73351,7 @@ "containerExtending": false, "left": 304, "top": 472, - "width": 128, + "width": 133.82373046875, "height": 10, "autoResize": false }, @@ -73257,7 +73375,7 @@ "containerExtending": false, "left": 304, "top": 482, - "width": 128, + "width": 133.82373046875, "height": 10, "autoResize": false }, @@ -73321,7 +73439,7 @@ "containerExtending": false, "left": 304, "top": 432, - "width": 128, + "width": 133.82373046875, "height": 60, "autoResize": false, "stereotypeDisplay": "label", @@ -73556,7 +73674,7 @@ "containerExtending": false, "left": 445, "top": 439, - "width": 130, + "width": 135.4208984375, "height": 13, "autoResize": false, "underline": false, @@ -73582,7 +73700,7 @@ "containerExtending": false, "left": 445, "top": 454, - "width": 130, + "width": 135.4208984375, "height": 13, "autoResize": false, "underline": false, @@ -73628,7 +73746,7 @@ "containerExtending": false, "left": 440, "top": 432, - "width": 140, + "width": 145.4208984375, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -73664,7 +73782,7 @@ "containerExtending": false, "left": 440, "top": 472, - "width": 140, + "width": 145.4208984375, "height": 10, "autoResize": false }, @@ -73688,7 +73806,7 @@ "containerExtending": false, "left": 440, "top": 482, - "width": 140, + "width": 145.4208984375, "height": 10, "autoResize": false }, @@ -73752,7 +73870,7 @@ "containerExtending": false, "left": 440, "top": 432, - "width": 140, + "width": 145.4208984375, "height": 60, "autoResize": false, "stereotypeDisplay": "label", @@ -73953,7 +74071,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 537, + "left": 686, "top": 232, "width": 0, "height": 13, @@ -73987,7 +74105,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 537, + "left": 686, "top": 217, "width": 0, "height": 13, @@ -74021,7 +74139,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 537, + "left": 686, "top": 262, "width": 0, "height": 13, @@ -74054,7 +74172,7 @@ "$ref": "AAAAAAFk73zjJlOEXDY=" }, "lineStyle": 0, - "points": "515:253;560:253", + "points": "525:253;848:253", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -74912,7 +75030,7 @@ "$ref": "AAAAAAFk732ViVR1WXM=" }, "lineStyle": 0, - "points": "464:432;464:312;294:312", + "points": "464:432;464:312;314:312", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -74961,8 +75079,8 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 188, - "top": -752, + "left": 268, + "top": -784, "width": 0, "height": 13, "autoResize": false, @@ -74986,9 +75104,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 813, - "top": 47, - "width": 373, + "left": 853, + "top": 31, + "width": 408.12255859375, "height": 13, "autoResize": false, "underline": false, @@ -75012,9 +75130,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 813, - "top": 62, - "width": 373, + "left": 853, + "top": 46, + "width": 408.12255859375, "height": 13, "autoResize": false, "underline": false, @@ -75038,8 +75156,8 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 188, - "top": -752, + "left": 268, + "top": -784, "width": 0, "height": 13, "autoResize": false, @@ -75058,9 +75176,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 808, - "top": 40, - "width": 383, + "left": 848, + "top": 24, + "width": 418.12255859375, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -75094,9 +75212,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 808, - "top": 80, - "width": 383, + "left": 848, + "top": 64, + "width": 418.12255859375, "height": 10, "autoResize": false }, @@ -75128,9 +75246,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 813, - "top": 95, - "width": 373, + "left": 853, + "top": 79, + "width": 408.12255859375, "height": 13, "autoResize": false, "underline": true, @@ -75157,9 +75275,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 813, - "top": 110, - "width": 373, + "left": 853, + "top": 94, + "width": 408.12255859375, "height": 13, "autoResize": false, "underline": true, @@ -75186,9 +75304,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 813, - "top": 125, - "width": 373, + "left": 853, + "top": 109, + "width": 408.12255859375, "height": 13, "autoResize": false, "underline": true, @@ -75215,9 +75333,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 813, - "top": 140, - "width": 373, + "left": 853, + "top": 124, + "width": 408.12255859375, "height": 13, "autoResize": false, "underline": true, @@ -75244,9 +75362,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 813, - "top": 155, - "width": 373, + "left": 853, + "top": 139, + "width": 408.12255859375, "height": 13, "autoResize": false, "underline": true, @@ -75273,9 +75391,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 813, - "top": 170, - "width": 373, + "left": 853, + "top": 154, + "width": 408.12255859375, "height": 13, "autoResize": false, "underline": true, @@ -75302,9 +75420,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 813, - "top": 185, - "width": 373, + "left": 853, + "top": 169, + "width": 408.12255859375, "height": 13, "autoResize": false, "underline": true, @@ -75331,9 +75449,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 813, - "top": 200, - "width": 373, + "left": 853, + "top": 184, + "width": 408.12255859375, "height": 13, "autoResize": false, "underline": true, @@ -75360,9 +75478,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 813, - "top": 215, - "width": 373, + "left": 853, + "top": 199, + "width": 408.12255859375, "height": 13, "autoResize": false, "underline": true, @@ -75389,9 +75507,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 813, - "top": 230, - "width": 373, + "left": 853, + "top": 214, + "width": 408.12255859375, "height": 13, "autoResize": false, "underline": true, @@ -75410,9 +75528,9 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 808, - "top": 90, - "width": 383, + "left": 848, + "top": 74, + "width": 418.12255859375, "height": 158, "autoResize": false }, @@ -75434,8 +75552,8 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 94, - "top": -376, + "left": 134, + "top": -392, "width": 10, "height": 10, "autoResize": false @@ -75458,8 +75576,8 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 94, - "top": -376, + "left": 134, + "top": -392, "width": 10, "height": 10, "autoResize": false @@ -75474,9 +75592,9 @@ "showShadow": true, "containerChangeable": true, "containerExtending": false, - "left": 808, - "top": 40, - "width": 383, + "left": 848, + "top": 24, + "width": 418.12255859375, "height": 208, "autoResize": false, "stereotypeDisplay": "label", @@ -75534,7 +75652,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 693, + "left": 722, "top": 123, "width": 0, "height": 13, @@ -75568,7 +75686,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 693, + "left": 722, "top": 108, "width": 0, "height": 13, @@ -75602,7 +75720,7 @@ "showShadow": true, "containerChangeable": false, "containerExtending": false, - "left": 693, + "left": 722, "top": 153, "width": 0, "height": 13, @@ -75635,7 +75753,7 @@ "$ref": "AAAAAAFk73whtFLUsGQ=" }, "lineStyle": 0, - "points": "578:144;808:144", + "points": "596:144;848:144", "stereotypeDisplay": "label", "showVisibility": true, "showProperty": true, @@ -75648,6 +75766,1730 @@ "propertyLabel": { "$ref": "AAAAAAFk74PZ3VylNUo=" } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk9MjwJKgabnk=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk9MRfHagAcBw=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk9MjwJagbi5I=", + "_parent": { + "$ref": "AAAAAAFk9MjwJKgabnk=" + }, + "model": { + "$ref": "AAAAAAFk9MRfHagAcBw=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk9MjwJagcfx8=", + "_parent": { + "$ref": "AAAAAAFk9MjwJagbi5I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1088, + "top": -182, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk9MjwJagd6qk=", + "_parent": { + "$ref": "AAAAAAFk9MjwJagbi5I=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 597, + "top": 439, + "width": 168, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageFLCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk9MjwJage7Ho=", + "_parent": { + "$ref": "AAAAAAFk9MjwJagbi5I=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 597, + "top": 454, + "width": 168, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage-external)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk9MjwJagfsac=", + "_parent": { + "$ref": "AAAAAAFk9MjwJagbi5I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1088, + "top": -182, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 592, + "top": 432, + "width": 178, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk9MjwJagcfx8=" + }, + "nameLabel": { + "$ref": "AAAAAAFk9MjwJagd6qk=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk9MjwJage7Ho=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk9MjwJagfsac=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk9MjwJagg4zY=", + "_parent": { + "$ref": "AAAAAAFk9MjwJKgabnk=" + }, + "model": { + "$ref": "AAAAAAFk9MRfHagAcBw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 592, + "top": 472, + "width": 178, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk9MjwJqghQv4=", + "_parent": { + "$ref": "AAAAAAFk9MjwJKgabnk=" + }, + "model": { + "$ref": "AAAAAAFk9MRfHagAcBw=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 592, + "top": 482, + "width": 178, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk9MjwJqgiE5g=", + "_parent": { + "$ref": "AAAAAAFk9MjwJKgabnk=" + }, + "model": { + "$ref": "AAAAAAFk9MRfHagAcBw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 544, + "top": -91, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk9MjwJqgjp0Y=", + "_parent": { + "$ref": "AAAAAAFk9MjwJKgabnk=" + }, + "model": { + "$ref": "AAAAAAFk9MRfHagAcBw=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 544, + "top": -91, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 592, + "top": 432, + "width": 178, + "height": 60, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk9MjwJagbi5I=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk9MjwJagg4zY=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk9MjwJqghQv4=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk9MjwJqgiE5g=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk9MjwJqgjp0Y=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk9MkD66hC2wM=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk9MSxhqgEZag=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk9MkD66hD/1I=", + "_parent": { + "$ref": "AAAAAAFk9MkD66hC2wM=" + }, + "model": { + "$ref": "AAAAAAFk9MSxhqgEZag=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk9MkD66hEuSI=", + "_parent": { + "$ref": "AAAAAAFk9MkD66hD/1I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1022, + "top": -20, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk9MkD66hF2xI=", + "_parent": { + "$ref": "AAAAAAFk9MkD66hD/1I=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 797, + "top": 511, + "width": 168, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageBPGCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk9MkD66hGM3A=", + "_parent": { + "$ref": "AAAAAAFk9MkD66hD/1I=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 797, + "top": 526, + "width": 168, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage-external)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk9MkD66hHyoU=", + "_parent": { + "$ref": "AAAAAAFk9MkD66hD/1I=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1022, + "top": -20, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 792, + "top": 504, + "width": 178, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk9MkD66hEuSI=" + }, + "nameLabel": { + "$ref": "AAAAAAFk9MkD66hF2xI=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk9MkD66hGM3A=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk9MkD66hHyoU=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk9MkD7KhIrbw=", + "_parent": { + "$ref": "AAAAAAFk9MkD66hC2wM=" + }, + "model": { + "$ref": "AAAAAAFk9MSxhqgEZag=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 792, + "top": 544, + "width": 178, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk9MkD7KhJMLM=", + "_parent": { + "$ref": "AAAAAAFk9MkD66hC2wM=" + }, + "model": { + "$ref": "AAAAAAFk9MSxhqgEZag=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 792, + "top": 554, + "width": 178, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk9MkD7KhKSUQ=", + "_parent": { + "$ref": "AAAAAAFk9MkD66hC2wM=" + }, + "model": { + "$ref": "AAAAAAFk9MSxhqgEZag=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 511, + "top": -10, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk9MkD7KhLrFg=", + "_parent": { + "$ref": "AAAAAAFk9MkD66hC2wM=" + }, + "model": { + "$ref": "AAAAAAFk9MSxhqgEZag=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 511, + "top": -10, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 792, + "top": 504, + "width": 178, + "height": 60, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk9MkD66hD/1I=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk9MkD7KhIrbw=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk9MkD7KhJMLM=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk9MkD7KhKSUQ=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk9MkD7KhLrFg=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk9MkVbKhqSa0=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk9Mbgf6gMd5c=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk9MkVbKhr7OM=", + "_parent": { + "$ref": "AAAAAAFk9MkVbKhqSa0=" + }, + "model": { + "$ref": "AAAAAAFk9Mbgf6gMd5c=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk9MkVbKhsy40=", + "_parent": { + "$ref": "AAAAAAFk9MkVbKhr7OM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1000, + "top": -200, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk9MkVbKhtfXk=", + "_parent": { + "$ref": "AAAAAAFk9MkVbKhr7OM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 797, + "top": 439, + "width": 170, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImagePhotosLoader", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk9MkVbKhuUpo=", + "_parent": { + "$ref": "AAAAAAFk9MkVbKhr7OM=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 797, + "top": 454, + "width": 170, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage-external)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk9MkVbKhvJVY=", + "_parent": { + "$ref": "AAAAAAFk9MkVbKhr7OM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 1000, + "top": -200, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 792, + "top": 432, + "width": 180, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk9MkVbKhsy40=" + }, + "nameLabel": { + "$ref": "AAAAAAFk9MkVbKhtfXk=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk9MkVbKhuUpo=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk9MkVbKhvJVY=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk9MkVbKhwFp4=", + "_parent": { + "$ref": "AAAAAAFk9MkVbKhqSa0=" + }, + "model": { + "$ref": "AAAAAAFk9Mbgf6gMd5c=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 792, + "top": 472, + "width": 180, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk9MkVbKhxbkc=", + "_parent": { + "$ref": "AAAAAAFk9MkVbKhqSa0=" + }, + "model": { + "$ref": "AAAAAAFk9Mbgf6gMd5c=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 792, + "top": 482, + "width": 180, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk9MkVbKhygDU=", + "_parent": { + "$ref": "AAAAAAFk9MkVbKhqSa0=" + }, + "model": { + "$ref": "AAAAAAFk9Mbgf6gMd5c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 500, + "top": -100, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk9MkVbKhzZdQ=", + "_parent": { + "$ref": "AAAAAAFk9MkVbKhqSa0=" + }, + "model": { + "$ref": "AAAAAAFk9Mbgf6gMd5c=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 500, + "top": -100, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 792, + "top": 432, + "width": 180, + "height": 60, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk9MkVbKhr7OM=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk9MkVbKhwFp4=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk9MkVbKhxbkc=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk9MkVbKhygDU=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk9MkVbKhzZdQ=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAFk9MlF5KjS7AI=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk9MToV6gIYTs=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAFk9MlF5KjTL+0=", + "_parent": { + "$ref": "AAAAAAFk9MlF5KjS7AI=" + }, + "model": { + "$ref": "AAAAAAFk9MToV6gIYTs=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAFk9MlF5KjUJZs=", + "_parent": { + "$ref": "AAAAAAFk9MlF5KjTL+0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -144, + "top": -62, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk9MlF5KjVShg=", + "_parent": { + "$ref": "AAAAAAFk9MlF5KjTL+0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;1", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 597, + "top": 511, + "width": 168, + "height": 13, + "autoResize": false, + "underline": false, + "text": "SDWebImageHEIFCoder", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk9MlF5KjWxZQ=", + "_parent": { + "$ref": "AAAAAAFk9MlF5KjTL+0=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 597, + "top": 526, + "width": 168, + "height": 13, + "autoResize": false, + "underline": false, + "text": "(from SDWebImage-external)", + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "LabelView", + "_id": "AAAAAAFk9MlF5KjX/bw=", + "_parent": { + "$ref": "AAAAAAFk9MlF5KjTL+0=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -144, + "top": -62, + "width": 0, + "height": 13, + "autoResize": false, + "underline": false, + "horizontalAlignment": 1, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 592, + "top": 504, + "width": 178, + "height": 40, + "autoResize": false, + "stereotypeLabel": { + "$ref": "AAAAAAFk9MlF5KjUJZs=" + }, + "nameLabel": { + "$ref": "AAAAAAFk9MlF5KjVShg=" + }, + "namespaceLabel": { + "$ref": "AAAAAAFk9MlF5KjWxZQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk9MlF5KjX/bw=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAFk9MlF5KjYf1I=", + "_parent": { + "$ref": "AAAAAAFk9MlF5KjS7AI=" + }, + "model": { + "$ref": "AAAAAAFk9MToV6gIYTs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 592, + "top": 544, + "width": 178, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAFk9MlF5KjZQtE=", + "_parent": { + "$ref": "AAAAAAFk9MlF5KjS7AI=" + }, + "model": { + "$ref": "AAAAAAFk9MToV6gIYTs=" + }, + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 592, + "top": 554, + "width": 178, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAFk9MlF5Kjaa7E=", + "_parent": { + "$ref": "AAAAAAFk9MlF5KjS7AI=" + }, + "model": { + "$ref": "AAAAAAFk9MToV6gIYTs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -72, + "top": -31, + "width": 10, + "height": 10, + "autoResize": false + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAFk9MlF5Kjb97I=", + "_parent": { + "$ref": "AAAAAAFk9MlF5KjS7AI=" + }, + "model": { + "$ref": "AAAAAAFk9MToV6gIYTs=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": -72, + "top": -31, + "width": 10, + "height": 10, + "autoResize": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": true, + "containerExtending": false, + "left": 592, + "top": 504, + "width": 178, + "height": 60, + "autoResize": false, + "stereotypeDisplay": "label", + "showVisibility": true, + "showNamespace": true, + "showProperty": true, + "showType": true, + "nameCompartment": { + "$ref": "AAAAAAFk9MlF5KjTL+0=" + }, + "wordWrap": false, + "suppressAttributes": false, + "suppressOperations": false, + "suppressReceptions": true, + "showMultiplicity": true, + "showOperationSignature": true, + "attributeCompartment": { + "$ref": "AAAAAAFk9MlF5KjYf1I=" + }, + "operationCompartment": { + "$ref": "AAAAAAFk9MlF5KjZQtE=" + }, + "receptionCompartment": { + "$ref": "AAAAAAFk9MlF5Kjaa7E=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAFk9MlF5Kjb97I=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk9MpUR6lCPW0=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk9MpUR6lBM+g=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk9MpUR6lDj8Y=", + "_parent": { + "$ref": "AAAAAAFk9MpUR6lCPW0=" + }, + "model": { + "$ref": "AAAAAAFk9MpUR6lBM+g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 667, + "top": 209, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk9MpUR6lCPW0=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk9MpUR6lEdSY=", + "_parent": { + "$ref": "AAAAAAFk9MpUR6lCPW0=" + }, + "model": { + "$ref": "AAAAAAFk9MpUR6lBM+g=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 667, + "top": 224, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk9MpUR6lCPW0=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk9MpUSKlFFXw=", + "_parent": { + "$ref": "AAAAAAFk9MpUR6lCPW0=" + }, + "model": { + "$ref": "AAAAAAFk9MpUR6lBM+g=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 668, + "top": 179, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk9MpUR6lCPW0=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73whtFLUsGQ=" + }, + "tail": { + "$ref": "AAAAAAFk9MjwJKgabnk=" + }, + "lineStyle": 0, + "points": "760:432;760:200;576:200;576:147", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk9MpUR6lDj8Y=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk9MpUR6lEdSY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk9MpUSKlFFXw=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk9MpmRalTc1A=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk9MpmRalSMfM=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk9MpmRalU7z0=", + "_parent": { + "$ref": "AAAAAAFk9MpmRalTc1A=" + }, + "model": { + "$ref": "AAAAAAFk9MpmRalSMfM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 687, + "top": 209, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk9MpmRalTc1A=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk9MpmRalVsUM=", + "_parent": { + "$ref": "AAAAAAFk9MpmRalTc1A=" + }, + "model": { + "$ref": "AAAAAAFk9MpmRalSMfM=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 687, + "top": 224, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk9MpmRalTc1A=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk9MpmRqlWAhc=", + "_parent": { + "$ref": "AAAAAAFk9MpmRalTc1A=" + }, + "model": { + "$ref": "AAAAAAFk9MpmRalSMfM=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 688, + "top": 179, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk9MpmRalTc1A=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73whtFLUsGQ=" + }, + "tail": { + "$ref": "AAAAAAFk9MkVbKhqSa0=" + }, + "lineStyle": 0, + "points": "800:432;800:200;576:200;576:147", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk9MpmRalU7z0=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk9MpmRalVsUM=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk9MpmRqlWAhc=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk9MpyLalkoms=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk9MpyLaljD/M=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk9MpyLallO/0=", + "_parent": { + "$ref": "AAAAAAFk9MpyLalkoms=" + }, + "model": { + "$ref": "AAAAAAFk9MpyLaljD/M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 775, + "top": 209, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk9MpyLalkoms=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk9MpyLalmEyY=", + "_parent": { + "$ref": "AAAAAAFk9MpyLalkoms=" + }, + "model": { + "$ref": "AAAAAAFk9MpyLaljD/M=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 775, + "top": 224, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk9MpyLalkoms=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk9MpyLaln3CA=", + "_parent": { + "$ref": "AAAAAAFk9MpyLalkoms=" + }, + "model": { + "$ref": "AAAAAAFk9MpyLaljD/M=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 776, + "top": 179, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk9MpyLalkoms=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73whtFLUsGQ=" + }, + "tail": { + "$ref": "AAAAAAFk9MlF5KjS7AI=" + }, + "lineStyle": 0, + "points": "769:528;776:528;776:200;576:200;576:147", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk9MpyLallO/0=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk9MpyLalmEyY=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk9MpyLaln3CA=" + } + }, + { + "_type": "UMLInterfaceRealizationView", + "_id": "AAAAAAFk9MqCl6l15ds=", + "_parent": { + "$ref": "AAAAAAFk73uRhlJQp8M=" + }, + "model": { + "$ref": "AAAAAAFk9MqCl6l0L/Q=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk9MqCl6l24lk=", + "_parent": { + "$ref": "AAAAAAFk9MqCl6l15ds=" + }, + "model": { + "$ref": "AAAAAAFk9MqCl6l0L/Q=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 783, + "top": 209, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk9MqCl6l15ds=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk9MqCl6l3ss8=", + "_parent": { + "$ref": "AAAAAAFk9MqCl6l15ds=" + }, + "model": { + "$ref": "AAAAAAFk9MqCl6l0L/Q=" + }, + "visible": null, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 783, + "top": 224, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAFk9MqCl6l15ds=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAFk9MqCl6l4aIs=", + "_parent": { + "$ref": "AAAAAAFk9MqCl6l15ds=" + }, + "model": { + "$ref": "AAAAAAFk9MqCl6l0L/Q=" + }, + "visible": false, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "left": 784, + "top": 179, + "width": 0, + "height": 13, + "autoResize": false, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAFk9MqCl6l15ds=" + }, + "edgePosition": 1, + "underline": false, + "horizontalAlignment": 2, + "verticalAlignment": 5, + "wordWrap": false + } + ], + "visible": true, + "enabled": true, + "lineColor": "#000000", + "fillColor": "#ffffff", + "fontColor": "#000000", + "font": "Arial;13;0", + "showShadow": true, + "containerChangeable": false, + "containerExtending": false, + "head": { + "$ref": "AAAAAAFk73whtFLUsGQ=" + }, + "tail": { + "$ref": "AAAAAAFk9MkD66hC2wM=" + }, + "lineStyle": 0, + "points": "792:528;784:528;784:200;576:200;576:147", + "stereotypeDisplay": "label", + "showVisibility": true, + "showProperty": true, + "nameLabel": { + "$ref": "AAAAAAFk9MqCl6l24lk=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAFk9MqCl6l3ss8=" + }, + "propertyLabel": { + "$ref": "AAAAAAFk9MqCl6l4aIs=" + } } ] }, @@ -76003,7 +77845,7 @@ "containerExtending": false, "left": 216, "top": 69, - "width": 464, + "width": 491.42529296875, "height": 83, "autoResize": false }, @@ -77020,7 +78862,7 @@ "containerExtending": false, "left": 280, "top": 356, - "width": 424, + "width": 449.60693359375, "height": 323, "autoResize": false }, @@ -77574,7 +79416,7 @@ "containerExtending": false, "left": 784, "top": 288, - "width": 194, + "width": 205.48876953125, "height": 83, "autoResize": false }, @@ -78067,7 +79909,7 @@ "containerExtending": false, "left": 8, "top": 288, - "width": 210, + "width": 210.82080078125, "height": 113, "autoResize": false }, @@ -78523,7 +80365,7 @@ "containerExtending": false, "left": 784, "top": 16, - "width": 153, + "width": 161.4677734375, "height": 53, "autoResize": false, "stereotypeLabel": { @@ -78860,7 +80702,7 @@ "containerExtending": false, "left": 784, "top": 69, - "width": 153, + "width": 157.087890625, "height": 113, "autoResize": false } @@ -79397,7 +81239,7 @@ "containerExtending": false, "left": 504, "top": 797, - "width": 162, + "width": 163.65771484375, "height": 158, "autoResize": false }, @@ -80254,7 +82096,7 @@ "containerExtending": false, "left": 312, "top": 797, - "width": 179, + "width": 185.17626953125, "height": 83, "autoResize": false }, @@ -80482,7 +82324,7 @@ "containerExtending": false, "left": 520, "top": 1008, - "width": 128, + "width": 133.82373046875, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -80913,7 +82755,7 @@ "containerExtending": false, "left": 328, "top": 1008, - "width": 128, + "width": 133.82373046875, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -81201,7 +83043,7 @@ "containerExtending": false, "left": 160, "top": 1008, - "width": 112, + "width": 123.2548828125, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -82340,7 +84182,7 @@ "containerExtending": false, "left": 8, "top": 472, - "width": 264, + "width": 279.59130859375, "height": 53, "autoResize": false, "stereotypeLabel": { @@ -83614,7 +85456,7 @@ "containerExtending": false, "left": 280, "top": 69, - "width": 537, + "width": 569.43798828125, "height": 38, "autoResize": false }, @@ -83938,7 +85780,7 @@ "containerExtending": false, "left": 16, "top": 216, - "width": 212, + "width": 219.37744140625, "height": 38, "autoResize": false }, @@ -84805,7 +86647,7 @@ "containerExtending": false, "left": 288, "top": 314, - "width": 523, + "width": 561.32568359375, "height": 98, "autoResize": false }, @@ -85176,7 +87018,7 @@ "containerExtending": false, "left": 896, "top": 264, - "width": 208, + "width": 221.4404296875, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -85870,7 +87712,7 @@ "containerExtending": false, "left": 608, "top": 592, - "width": 268, + "width": 287.20849609375, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -86190,7 +88032,7 @@ "containerExtending": false, "left": 584, "top": 464, - "width": 278, + "width": 287.20849609375, "height": 53, "autoResize": false, "stereotypeLabel": { @@ -86804,7 +88646,7 @@ "containerExtending": false, "left": 16, "top": 677, - "width": 282, + "width": 300.3798828125, "height": 128, "autoResize": false }, @@ -87032,7 +88874,7 @@ "containerExtending": false, "left": 312, "top": 464, - "width": 193, + "width": 205.27294921875, "height": 40, "autoResize": false, "stereotypeLabel": { @@ -87505,7 +89347,7 @@ "containerExtending": false, "left": 16, "top": 504, - "width": 260, + "width": 278.2138671875, "height": 38, "autoResize": false }, @@ -88078,7 +89920,7 @@ "containerExtending": false, "left": 896, "top": 16, - "width": 216, + "width": 230.1494140625, "height": 53, "autoResize": false, "stereotypeLabel": { diff --git a/Docs/Diagrams/SDWebImageCodersClassDiagram.png b/Docs/Diagrams/SDWebImageCodersClassDiagram.png index 166fbdf5dd43df785b78dc6d8184cfcb56e3c155..efd32291707387229cc20a5a141402bbf778aba3 100644 GIT binary patch literal 142417 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
W(jINf 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 literal 113615 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ξ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 D^R_-c From cb8879f56ae161dd7049b1c83b107ece0fb6b884 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 1 Aug 2018 20:52:50 +0800 Subject: [PATCH 226/361] Fix that using `NS_TYPED_ENUM` on `SDImageFormat` cause the existing Swift API naming changed --- SDWebImage/NSData+ImageContentType.h | 2 +- SDWebImage/SDImageCoder.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SDWebImage/NSData+ImageContentType.h b/SDWebImage/NSData+ImageContentType.h index c5970cb4..3555c49b 100644 --- a/SDWebImage/NSData+ImageContentType.h +++ b/SDWebImage/NSData+ImageContentType.h @@ -40,7 +40,7 @@ static const SDImageFormat SDImageFormatHEIC = 5; * @param format Format as SDImageFormat * @return The UTType as CFStringRef */ -+ (nonnull CFStringRef)sd_UTTypeFromImageFormat:(SDImageFormat)format CF_RETURNS_NOT_RETAINED; ++ (nonnull CFStringRef)sd_UTTypeFromImageFormat:(SDImageFormat)format CF_RETURNS_NOT_RETAINED NS_SWIFT_NAME(sd_UTType(from:)); /** * Convert UTTyppe to SDImageFormat diff --git a/SDWebImage/SDImageCoder.h b/SDWebImage/SDImageCoder.h index 60b796ad..9084c6fb 100644 --- a/SDWebImage/SDImageCoder.h +++ b/SDWebImage/SDImageCoder.h @@ -89,7 +89,7 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderWebImageContext; @param format The image format @return YES if this coder can encode the image, NO otherwise */ -- (BOOL)canEncodeToFormat:(SDImageFormat)format; +- (BOOL)canEncodeToFormat:(SDImageFormat)format NS_SWIFT_NAME(canEncode(to:)); /** Encode the image to image data. From 892267af74bd2e04edd451d218b56ae4b880486a Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 2 Aug 2018 11:07:53 +0800 Subject: [PATCH 227/361] Fix that downloader options about image decoding is not correctly set --- SDWebImage/SDImageCacheDefine.m | 10 +++++----- SDWebImage/SDImageLoader.m | 20 ++++++++++---------- SDWebImage/SDWebImageDownloader.m | 3 +++ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/SDWebImage/SDImageCacheDefine.m b/SDWebImage/SDImageCacheDefine.m index a729d7ad..68e9165b 100644 --- a/SDWebImage/SDImageCacheDefine.m +++ b/SDWebImage/SDImageCacheDefine.m @@ -33,13 +33,13 @@ UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSS } } if (!image) { - SDImageCoderOptions *options = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; + SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; if (context) { - SDImageCoderMutableOptions *mutableOptions = [options mutableCopy]; - [mutableOptions setValue:context forKey:SDImageCoderWebImageContext]; - options = [mutableOptions copy]; + SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy]; + [mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext]; + coderOptions = [mutableCoderOptions copy]; } - image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:options]; + image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:coderOptions]; } if (image) { BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; diff --git a/SDWebImage/SDImageLoader.m b/SDWebImage/SDImageLoader.m index 4fe35e0f..97f51686 100644 --- a/SDWebImage/SDImageLoader.m +++ b/SDWebImage/SDImageLoader.m @@ -47,13 +47,13 @@ UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Nonnull imageData, NS } } if (!image) { - SDImageCoderOptions *options = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; + SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; if (context) { - SDImageCoderMutableOptions *mutableOptions = [options mutableCopy]; - [mutableOptions setValue:context forKey:SDImageCoderWebImageContext]; - options = [mutableOptions copy]; + SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy]; + [mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext]; + coderOptions = [mutableCoderOptions copy]; } - image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:options]; + image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:coderOptions]; } if (image) { BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; @@ -125,13 +125,13 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im } } if (!image) { - SDImageCoderOptions *options = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; + SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; if (context) { - SDImageCoderMutableOptions *mutableOptions = [options mutableCopy]; - [mutableOptions setValue:context forKey:SDImageCoderWebImageContext]; - options = [mutableOptions copy]; + SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy]; + [mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext]; + coderOptions = [mutableCoderOptions copy]; } - image = [progressiveCoder incrementalDecodedImageWithOptions:options]; + image = [progressiveCoder incrementalDecodedImageWithOptions:coderOptions]; } if (image) { BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 7dd3c7aa..0350f7ac 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -488,6 +488,9 @@ didReceiveResponse:(NSURLResponse *)response if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates; if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority; if (options & SDWebImageScaleDownLargeImages) downloaderOptions |= SDWebImageDownloaderScaleDownLargeImages; + if (options & SDWebImageAvoidDecodeImage) downloaderOptions |= SDWebImageDownloaderAvoidDecodeImage; + if (options & SDWebImageDecodeFirstFrameOnly) downloaderOptions |= SDWebImageDownloaderDecodeFirstFrameOnly; + if (options & SDWebImagePreloadAllFrames) downloaderOptions |= SDWebImageDownloaderPreloadAllFrames; if (cachedImage && options & SDWebImageRefreshCached) { // force progressive off if image already cached but forced refreshing From 67e0df75c6be7a71afc6f9d4aa60a2a930cfb900 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 2 Aug 2018 12:08:18 +0800 Subject: [PATCH 228/361] Add one feature, to allow user to limit the progress interval and reduce the frequency of progress callback Also fix that progressive decoding should stop when all image data is downloaded --- SDWebImage/SDWebImageDownloader.m | 16 ++++++--- SDWebImage/SDWebImageDownloaderConfig.h | 9 +++++ SDWebImage/SDWebImageDownloaderConfig.m | 1 + SDWebImage/SDWebImageDownloaderOperation.h | 16 +++++++-- SDWebImage/SDWebImageDownloaderOperation.m | 38 +++++++++++++++++----- 5 files changed, 65 insertions(+), 15 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 7dd3c7aa..73449530 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -200,10 +200,18 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; } NSOperation *operation = [[operationClass alloc] initWithRequest:request inSession:sself.session options:options context:context]; - if (sself.config.urlCredential) { - operation.credential = sself.config.urlCredential; - } else if (sself.config.username && sself.config.password) { - operation.credential = [NSURLCredential credentialWithUser:sself.config.username password:sself.config.password persistence:NSURLCredentialPersistenceForSession]; + if ([operation respondsToSelector:@selector(setCredential:)]) { + if (sself.config.urlCredential) { + operation.credential = sself.config.urlCredential; + } else if (sself.config.username && sself.config.password) { + operation.credential = [NSURLCredential credentialWithUser:sself.config.username password:sself.config.password persistence:NSURLCredentialPersistenceForSession]; + } + } + + if ([operation respondsToSelector:@selector(setMinimumProgressInterval:)]) { + NSTimeInterval minimumProgressInterval = sself.config.minimumProgressInterval; + minimumProgressInterval = MIN(MAX(minimumProgressInterval, 0), 1); + operation.minimumProgressInterval = minimumProgressInterval; } if (options & SDWebImageDownloaderHighPriority) { diff --git a/SDWebImage/SDWebImageDownloaderConfig.h b/SDWebImage/SDWebImageDownloaderConfig.h index 1b5d833e..00f15496 100644 --- a/SDWebImage/SDWebImageDownloaderConfig.h +++ b/SDWebImage/SDWebImageDownloaderConfig.h @@ -41,6 +41,15 @@ typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { */ @property (nonatomic, assign) NSTimeInterval downloadTimeout; +/** + * The minimum interval about progress percent during network downloading. Which means the next progress callback and current progress callback's progress percent difference should be larger or equal to this value. + * The value should be 0.0-1.0. + * @note If you're using progressive decoding feature, this will also effect the image refresh rate. + * @note This value may enhance the performance if you don't want progress callback too frequently. + * Defaults to 0, which means each time we receive the new data from URLSession, we callback the progressBlock immediately. + */ +@property (nonatomic, assign) NSTimeInterval minimumProgressInterval; + /** * The custom session configuration in use by NSURLSession. If you don't provide one, we will use `defaultSessionConfiguration` instead. * Defatuls to nil. diff --git a/SDWebImage/SDWebImageDownloaderConfig.m b/SDWebImage/SDWebImageDownloaderConfig.m index 79e15c9d..1fc93308 100644 --- a/SDWebImage/SDWebImageDownloaderConfig.m +++ b/SDWebImage/SDWebImageDownloaderConfig.m @@ -34,6 +34,7 @@ static SDWebImageDownloaderConfig * _defaultDownloaderConfig; SDWebImageDownloaderConfig *config = [[[self class] allocWithZone:zone] init]; config.maxConcurrentDownloads = self.maxConcurrentDownloads; config.downloadTimeout = self.downloadTimeout; + config.minimumProgressInterval = self.minimumProgressInterval; config.sessionConfiguration = [self.sessionConfiguration copyWithZone:zone]; config.operationClass = self.operationClass; config.executionOrder = self.executionOrder; diff --git a/SDWebImage/SDWebImageDownloaderOperation.h b/SDWebImage/SDWebImageDownloaderOperation.h index c5edfb1e..ff5c6129 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.h +++ b/SDWebImage/SDWebImageDownloaderOperation.h @@ -36,9 +36,6 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification - (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock; -- (nullable NSURLCredential *)credential; -- (void)setCredential:(nullable NSURLCredential *)value; - - (BOOL)cancel:(nullable id)token; - (nullable NSURLRequest *)request; @@ -46,6 +43,10 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification @optional - (nullable NSURLSessionTask *)dataTask; +- (nullable NSURLCredential *)credential; +- (void)setCredential:(nullable NSURLCredential *)credential; +- (NSTimeInterval)minimumProgressInterval; +- (void)setMinimumProgressInterval:(NSTimeInterval)minimumProgressInterval; @end @@ -74,6 +75,15 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification */ @property (nonatomic, strong, nullable) NSURLCredential *credential; +/** + * The minimum interval about progress percent during network downloading. Which means the next progress callback and current progress callback's progress percent difference should be larger or equal to this value. + * The value should be 0.0-1.0. + * @note If you're using progressive decoding feature, this will also effect the image refresh rate. + * @note This value may enhance the performance if you don't want progress callback too frequently. + * Defaults to 0, which means each time we receive the new data from URLSession, we callback the progressBlock immediately. + */ +@property (assign, nonatomic) NSTimeInterval minimumProgressInterval; + /** * The options for the receiver. */ diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 5232400b..a6c13fa7 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -37,9 +37,11 @@ typedef NSMutableDictionary SDCallbacksDictionary; @property (assign, nonatomic, getter = isFinished) BOOL finished; @property (strong, nonatomic, nullable) NSMutableData *imageData; @property (copy, nonatomic, nullable) NSData *cachedData; // for `SDWebImageDownloaderIgnoreCachedResponse` -@property (assign, nonatomic, readwrite) NSUInteger expectedSize; +@property (assign, nonatomic) NSUInteger expectedSize; // may be 0 +@property (assign, nonatomic) NSUInteger receivedSize; @property (strong, nonatomic, nullable, readwrite) NSURLResponse *response; @property (strong, nonatomic, nullable) NSError *responseError; +@property (assign, nonatomic) double previousProgress; // previous progress percent // This is weak because it is injected by whoever manages this session. If this gets nil-ed out, we won't be able to run // the task associated with this operation @@ -331,17 +333,37 @@ didReceiveResponse:(NSURLResponse *)response self.imageData = [[NSMutableData alloc] initWithCapacity:self.expectedSize]; } [self.imageData appendData:data]; + + self.receivedSize = self.imageData.length; + if (self.expectedSize == 0) { + // Unknown expectedSize, immediately call progressBlock and return + for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) { + progressBlock(self.receivedSize, self.expectedSize, self.request.URL); + } + return; + } + + // Get the finish status + BOOL finished = (self.receivedSize >= self.expectedSize); + // Get the current progress + double currentProgress = (double)self.receivedSize / (double)self.expectedSize; + double previousProgress = self.previousProgress; + // Check if we need callback progress + if (currentProgress - previousProgress < self.minimumProgressInterval) { + return; + } + self.previousProgress = currentProgress; - if ((self.options & SDWebImageDownloaderProgressiveLoad) && self.expectedSize > 0) { + if (self.options & SDWebImageDownloaderProgressiveLoad) { // Get the image data NSData *imageData = [self.imageData copy]; - // Get the total bytes downloaded - const NSUInteger totalSize = imageData.length; - // Get the finish status - BOOL finished = (totalSize >= self.expectedSize); // progressive decode the image in coder queue dispatch_async(self.coderQueue, ^{ + // If all the data has already been downloaded, earily return to avoid further decoding + if (self.receivedSize >= self.expectedSize) { + return; + } UIImage *image = SDImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, finished, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); if (image) { // We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding. @@ -350,9 +372,9 @@ didReceiveResponse:(NSURLResponse *)response } }); } - + for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) { - progressBlock(self.imageData.length, self.expectedSize, self.request.URL); + progressBlock(self.receivedSize, self.expectedSize, self.request.URL); } } From 6a3aa484108970460c907ca9af825fb794ae990c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 2 Aug 2018 13:18:25 +0800 Subject: [PATCH 229/361] Update the test to ensure minimumProgressInterval works --- Tests/Tests/SDWebImageDownloaderTests.m | 28 +++++++++++++++++++ Tests/Tests/SDWebImageTestDownloadOperation.h | 1 - 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index e2cfe5d5..e1865f4d 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -265,6 +265,34 @@ [self waitForExpectationsWithCommonTimeout]; } +- (void)test17ThatMinimumProgressIntervalWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Minimum progress interval"]; + SDWebImageDownloaderConfig *config = SDWebImageDownloaderConfig.defaultDownloaderConfig; + config.minimumProgressInterval = 0.51; // This will make the progress only callback once + SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] initWithConfig:config]; + NSURL *imageURL = [NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp"]; + __block NSUInteger allProgressCount = 0; // All progress (including operation start / first HTTP response, etc) + __block NSUInteger validProgressCount = 0; // Only progress from `URLSession:dataTask:didReceiveData:` + [downloader downloadImageWithURL:imageURL options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { + allProgressCount++; + if (expectedSize <= 0 || receivedSize <= 0) { + // ignore the progress callback until we receive data + return; + } + validProgressCount++; + } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + if (allProgressCount > 1 && validProgressCount == 1) { + [expectation fulfill]; + } else { + XCTFail(@"Progress callback more than once"); + } + }]; + + [self waitForExpectationsWithCommonTimeoutUsingHandler:^(NSError * _Nullable error) { + [downloader invalidateSessionAndCancel:YES]; + }]; +} + /** * Per #883 - Fix multiple requests for same image and then canceling one * Old SDWebImage (3.x) could not handle correctly multiple requests for the same image + cancel diff --git a/Tests/Tests/SDWebImageTestDownloadOperation.h b/Tests/Tests/SDWebImageTestDownloadOperation.h index edc07b9c..6ecba328 100644 --- a/Tests/Tests/SDWebImageTestDownloadOperation.h +++ b/Tests/Tests/SDWebImageTestDownloadOperation.h @@ -15,7 +15,6 @@ */ @interface SDWebImageTestDownloadOperation : NSOperation -@property (nonatomic, strong, nullable) NSURLCredential *credential; @property (nonatomic, strong, nullable) NSURLRequest *request; @property (nonatomic, strong, nullable) NSURLResponse *response; From e400d220c521b279a5e6397bb4cee5afbec1c9c2 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 2 Aug 2018 18:53:52 +0800 Subject: [PATCH 230/361] Update the test from merge conflict --- Tests/Tests/SDWebImageDownloaderTests.m | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index 2c53ed75..1f050ce6 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -99,6 +99,17 @@ [downloader invalidateSessionAndCancel:YES]; } +- (void)test07ThatDownloadImageWithNilURLCallsCompletionWithNils { + XCTestExpectation *expectation = [self expectationWithDescription:@"Completion is called with nils"]; + [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:nil options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + expect(image).to.beNil(); + expect(data).to.beNil(); + expect(error.code).equal(SDWebImageErrorInvalidURL); + [expectation fulfill]; + }]; + [self waitForExpectationsWithCommonTimeout]; +} + - (void)test08ThatAHTTPAuthDownloadWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"HTTP Auth download"]; SDWebImageDownloaderConfig *config = SDWebImageDownloaderConfig.defaultDownloaderConfig; From 475e9a5b116904ca9c5b6a3dbf8d00251bfde2d4 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Thu, 2 Aug 2018 14:40:10 +0300 Subject: [PATCH 231/361] Added a bit more description to the way to contribute to this project. --- .github/CONTRIBUTING.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index b7b0e6d5..ce28bd03 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,7 +1,27 @@ # Contributing to SDWebImage +First of all, we want to thank you for you interest in this project. +Every contribution matters, this is how we are keeping the project alive. +We are all owners, from Olivier who started the project, to the people who use it in their projects and participated in a conversation, improved the documentation, created an example or made any code changes. +If you want to help, but don't know where to begin, we recommend you start small: +- it would help a lot if you read: https://opensource.guide/how-to-contribute/ +- read the ongoing discussions to see what the overall status is +- pitch in the converstations where you feel it's useful. Talk to other people, ask questions if you don't understand something +- contributing to the documentation or the ongoing converstations is as important as contributing to the code + We want to make contributing to this project as easy and transparent as possible. Here are a few guidelines for making all our lives easier. +## Contribute to ongoing conversations + +If you have a valid opinion about something we are talking about, feel free to share it. +If you also encountered an issue that someone else described, pitch in. Better yet, if you already fixed it in a certain way, share that. +We focus mostly on the GitHub conversations, but you can also help by going to the [questions tagged with "SDWebImage" on StackOverflow](https://stackoverflow.com/questions/tagged/sdwebimage) and getting involved. + +## Improving documentation + +A project's documentation is something you can always improve on. Make sure you go through the existing documentation and suggest changes or just create new pieces of documentation. +Examples are also welcome. + ## Asking questions We don't use GitHub as a support forum. For any usage questions that are not specific to the project itself, please ask on [Stack Overflow](https://stackoverflow.com/) instead. By doing so, you'll be more likely to quickly solve your problem, and you'll allow anyone else with the same question to find the answer. This also allows maintainers to focus on improving the project for others. From d9d0b7d4bf26b29501ffec5eef858f959ebf3967 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 3 Aug 2018 17:19:43 +0800 Subject: [PATCH 232/361] Add the feature, to migrate the disk cache from 4.x version to the new location of cache path. --- SDWebImage/SDDiskCache.h | 11 +++++++++++ SDWebImage/SDDiskCache.m | 29 +++++++++++++++++++++++++++++ SDWebImage/SDImageCache.m | 14 ++++++++++++++ Tests/Tests/SDImageCacheTests.m | 22 +++++++++++++++++++++- 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/SDWebImage/SDDiskCache.h b/SDWebImage/SDDiskCache.h index 0a12ff31..7860c613 100644 --- a/SDWebImage/SDDiskCache.h +++ b/SDWebImage/SDDiskCache.h @@ -104,4 +104,15 @@ - (nonnull instancetype)init NS_UNAVAILABLE; +/** + Move the cache directory from old location to new location, the old location will be removed after finish. + If the old location does not exist, does nothing. + If the new location does not exist, only do a movement of directory. + If the new location does exist, will move and merge the files from old location. + + @param srcPath old location of cache directory + @param dstPath new location of cache directory + */ +- (void)moveCacheDirectoryFromPath:(nonnull NSString *)srcPath toPath:(nonnull NSString *)dstPath; + @end diff --git a/SDWebImage/SDDiskCache.m b/SDWebImage/SDDiskCache.m index 9c3e4d39..457a3d39 100644 --- a/SDWebImage/SDDiskCache.m +++ b/SDWebImage/SDDiskCache.m @@ -228,6 +228,35 @@ return [path stringByAppendingPathComponent:filename]; } +- (void)moveCacheDirectoryFromPath:(nonnull NSString *)srcPath toPath:(nonnull NSString *)dstPath { + NSParameterAssert(srcPath); + NSParameterAssert(dstPath); + BOOL isDirectory; + // Check if old path is directory + if (![self.fileManager fileExistsAtPath:srcPath isDirectory:&isDirectory] || !isDirectory) { + return; + } + // Check if new path is directory + if (![self.fileManager fileExistsAtPath:dstPath isDirectory:&isDirectory]) { + // New directory does not exist, rename directory + [self.fileManager moveItemAtPath:srcPath toPath:dstPath error:nil]; + } else { + if (!isDirectory) { + // New path is not directory, remove directory + [self.fileManager removeItemAtPath:dstPath error:nil]; + } + // New directory exist, merge the files + NSDirectoryEnumerator *dirEnumerator = [self.fileManager enumeratorAtPath:srcPath]; + NSString *file; + while ((file = [dirEnumerator nextObject])) { + // Don't handle error, just try to move. + [self.fileManager moveItemAtPath:[srcPath stringByAppendingPathComponent:file] toPath:[dstPath stringByAppendingPathComponent:file] error:nil]; + } + } + // Remove the old path + [self.fileManager removeItemAtPath:srcPath error:nil]; +} + #pragma mark - Hash static inline NSString * _Nullable SDDiskCacheFileNameForKey(NSString * _Nullable key) { diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 96ec13bc..57f53757 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -86,6 +86,7 @@ NSAssert([config.diskCacheClass conformsToProtocol:@protocol(SDDiskCache)], @"Custom disk cache class must conform to `SDDiskCache` protocol"); _diskCache = [[config.diskCacheClass alloc] initWithCachePath:_diskCachePath config:_config]; + [self migrateDiskCacheDirectory]; #if SD_UIKIT // Subscribe to app events @@ -128,6 +129,19 @@ return [paths[0] stringByAppendingPathComponent:fullNamespace]; } +- (void)migrateDiskCacheDirectory { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if ([self.diskCache isKindOfClass:[SDDiskCache class]]) { + NSString *newDefaultPath = [[self makeDiskCachePath:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDImageCache.default"]; + NSString *oldDefaultPath = [[self makeDiskCachePath:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDWebImageCache.default"]; + dispatch_async(self.ioQueue, ^{ + [((SDDiskCache *)self.diskCache) moveCacheDirectoryFromPath:oldDefaultPath toPath:newDefaultPath]; + }); + } + }); +} + #pragma mark - Store Ops - (void)storeImage:(nullable UIImage *)image diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index ce14a950..06e71df3 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -21,7 +21,8 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; @end -@interface SDImageCacheTests : SDTestCase +@interface SDImageCacheTests : SDTestCase + @end @implementation SDImageCacheTests @@ -359,6 +360,25 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; expect([diskCache isKindOfClass:[SDWebImageTestDiskCache class]]).to.beTruthy(); } +- (void)test44DiskCacheMigrationFromOldVersion { + SDImageCacheConfig *config = [[SDImageCacheConfig alloc] init]; + NSFileManager *fileManager = [[NSFileManager alloc] init]; + config.fileManager = fileManager; + + // Fake to store a.png into old path + NSString *newDefaultPath = [[self makeDiskCachePath:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDImageCache.default"]; + NSString *oldDefaultPath = [[self makeDiskCachePath:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDWebImageCache.default"]; + [fileManager createDirectoryAtPath:oldDefaultPath withIntermediateDirectories:YES attributes:nil error:nil]; + [fileManager createFileAtPath:[oldDefaultPath stringByAppendingPathComponent:@"a.png"] contents:[NSData dataWithContentsOfFile:[self testPNGPath]] attributes:nil]; + // Call migration + SDDiskCache *diskCache = [[SDDiskCache alloc] initWithCachePath:newDefaultPath config:config]; + [diskCache moveCacheDirectoryFromPath:oldDefaultPath toPath:newDefaultPath]; + + // Expect a.png into new path + BOOL exist = [fileManager fileExistsAtPath:[newDefaultPath stringByAppendingPathComponent:@"a.png"]]; + expect(exist).beTruthy(); +} + #pragma mark - SDImageCache & SDImageCachesManager - (void)test50SDImageCacheQueryOp { XCTestExpectation *expectation = [self expectationWithDescription:@"SDImageCache query op works"]; From 3863264a13567303c8e8d53c140aca986a9ce5c2 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 3 Aug 2018 21:55:04 +0800 Subject: [PATCH 233/361] Improve the code robustness of disk cache migrate --- SDWebImage/SDDiskCache.m | 18 +++++++++++------- SDWebImage/SDImageCache.m | 16 +++++++++------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/SDWebImage/SDDiskCache.m b/SDWebImage/SDDiskCache.m index 457a3d39..00612c96 100644 --- a/SDWebImage/SDDiskCache.m +++ b/SDWebImage/SDDiskCache.m @@ -231,20 +231,24 @@ - (void)moveCacheDirectoryFromPath:(nonnull NSString *)srcPath toPath:(nonnull NSString *)dstPath { NSParameterAssert(srcPath); NSParameterAssert(dstPath); + // Check if old path is equal to new path + if ([srcPath isEqualToString:dstPath]) { + return; + } BOOL isDirectory; // Check if old path is directory if (![self.fileManager fileExistsAtPath:srcPath isDirectory:&isDirectory] || !isDirectory) { return; } // Check if new path is directory - if (![self.fileManager fileExistsAtPath:dstPath isDirectory:&isDirectory]) { + if (![self.fileManager fileExistsAtPath:dstPath isDirectory:&isDirectory] || !isDirectory) { + if (!isDirectory) { + // New path is not directory, remove file + [self.fileManager removeItemAtPath:dstPath error:nil]; + } // New directory does not exist, rename directory [self.fileManager moveItemAtPath:srcPath toPath:dstPath error:nil]; } else { - if (!isDirectory) { - // New path is not directory, remove directory - [self.fileManager removeItemAtPath:dstPath error:nil]; - } // New directory exist, merge the files NSDirectoryEnumerator *dirEnumerator = [self.fileManager enumeratorAtPath:srcPath]; NSString *file; @@ -252,9 +256,9 @@ // Don't handle error, just try to move. [self.fileManager moveItemAtPath:[srcPath stringByAppendingPathComponent:file] toPath:[dstPath stringByAppendingPathComponent:file] error:nil]; } + // Remove the old path + [self.fileManager removeItemAtPath:srcPath error:nil]; } - // Remove the old path - [self.fileManager removeItemAtPath:srcPath error:nil]; } #pragma mark - Hash diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 57f53757..e79fbdf2 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -86,6 +86,8 @@ NSAssert([config.diskCacheClass conformsToProtocol:@protocol(SDDiskCache)], @"Custom disk cache class must conform to `SDDiskCache` protocol"); _diskCache = [[config.diskCacheClass alloc] initWithCachePath:_diskCachePath config:_config]; + + // Check and migrate disk cache directory if need [self migrateDiskCacheDirectory]; #if SD_UIKIT @@ -124,22 +126,22 @@ return [self.diskCache cachePathForKey:key]; } -- (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace { +- (nullable NSString *)makeDiskCachePath:(nonnull NSString *)fullNamespace { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - return [paths[0] stringByAppendingPathComponent:fullNamespace]; + return [paths.firstObject stringByAppendingPathComponent:fullNamespace]; } - (void)migrateDiskCacheDirectory { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - if ([self.diskCache isKindOfClass:[SDDiskCache class]]) { + if ([self.diskCache isKindOfClass:[SDDiskCache class]]) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ NSString *newDefaultPath = [[self makeDiskCachePath:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDImageCache.default"]; NSString *oldDefaultPath = [[self makeDiskCachePath:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDWebImageCache.default"]; dispatch_async(self.ioQueue, ^{ [((SDDiskCache *)self.diskCache) moveCacheDirectoryFromPath:oldDefaultPath toPath:newDefaultPath]; }); - } - }); + }); + } } #pragma mark - Store Ops From 42caecf27ba8e999e1b3f15da27cf46e732ae9af Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 6 Aug 2018 11:18:00 +0800 Subject: [PATCH 234/361] Fix that `shouldUseWeakMemoryCache` code was lost during merge conflict --- SDWebImage/SDMemoryCache.m | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/SDWebImage/SDMemoryCache.m b/SDWebImage/SDMemoryCache.m index e434f4ec..45759650 100644 --- a/SDWebImage/SDMemoryCache.m +++ b/SDWebImage/SDMemoryCache.m @@ -84,6 +84,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext; // `setObject:forKey:` just call this with 0 cost. Override this is enough - (void)setObject:(id)obj forKey:(id)key cost:(NSUInteger)g { [super setObject:obj forKey:key cost:g]; + if (!self.config.shouldUseWeakMemoryCache) { + return; + } if (key && obj) { // Store weak cache LOCK(self.weakCacheLock); @@ -94,6 +97,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext; - (id)objectForKey:(id)key { id obj = [super objectForKey:key]; + if (!self.config.shouldUseWeakMemoryCache) { + return obj; + } if (key && !obj) { // Check weak cache LOCK(self.weakCacheLock); @@ -113,6 +119,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext; - (void)removeObjectForKey:(id)key { [super removeObjectForKey:key]; + if (!self.config.shouldUseWeakMemoryCache) { + return; + } if (key) { // Remove weak cache LOCK(self.weakCacheLock); @@ -123,6 +132,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext; - (void)removeAllObjects { [super removeAllObjects]; + if (!self.config.shouldUseWeakMemoryCache) { + return; + } // Manually remove should also remove weak cache LOCK(self.weakCacheLock); [self.weakCache removeAllObjects]; From 8cfda3dce91416988b028e50f142020b599ac688 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 8 Aug 2018 15:36:57 +0800 Subject: [PATCH 235/361] Make download receive response notification only dispatch to specific observer --- SDWebImage/SDWebImageDownloader.m | 14 +++++++------- SDWebImage/UIView+WebCacheOperation.m | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 4dc2e548..d10184d9 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -429,20 +429,20 @@ didReceiveResponse:(NSURLResponse *)response @implementation SDWebImageDownloadToken - (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self name:SDWebImageDownloadReceiveResponseNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:SDWebImageDownloadReceiveResponseNotification object:_downloadOperation]; } -- (instancetype)init { - self = [super init]; - if (self) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadReceiveResponse:) name:SDWebImageDownloadReceiveResponseNotification object:nil]; +- (void)setDownloadOperation:(NSOperation *)downloadOperation { + if (downloadOperation != _downloadOperation) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:SDWebImageDownloadReceiveResponseNotification object:_downloadOperation]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadReceiveResponse:) name:SDWebImageDownloadReceiveResponseNotification object:downloadOperation]; + _downloadOperation = downloadOperation; } - return self; } - (void)downloadReceiveResponse:(NSNotification *)notification { NSOperation *downloadOperation = notification.object; - if (downloadOperation && downloadOperation == self.downloadOperation) { + if (downloadOperation) { self.response = downloadOperation.response; } } diff --git a/SDWebImage/UIView+WebCacheOperation.m b/SDWebImage/UIView+WebCacheOperation.m index c3bfc1e8..83cec8aa 100644 --- a/SDWebImage/UIView+WebCacheOperation.m +++ b/SDWebImage/UIView+WebCacheOperation.m @@ -11,7 +11,7 @@ static char loadOperationKey; -// key is copy, value is weak because operation instance is retained by SDWebImageManager's runningOperations property +// key is strong, value is weak because operation instance is retained by SDWebImageManager's runningOperations property // we should use lock to keep thread-safe because these method may not be acessed from main queue typedef NSMapTable> SDOperationsDictionary; From ab5b5677b2370ccf4a0317ece18aa5c63b29e979 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 9 Aug 2018 14:59:04 +0800 Subject: [PATCH 236/361] Remove setter of downloadOperation --- SDWebImage/SDWebImageDownloader.h | 7 +++++++ SDWebImage/SDWebImageDownloader.m | 20 ++++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 351d57d1..b1d2d120 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -91,6 +91,8 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStopNotification; typedef SDImageLoaderProgressBlock SDWebImageDownloaderProgressBlock; typedef SDImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock; +@protocol SDWebImageDownloaderOperation; + /** * A token associated with each download. Can be used to cancel a download */ @@ -116,6 +118,11 @@ typedef SDImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock; */ @property (nonatomic, strong, nullable, readonly) NSURLResponse *response; +/** + Init download token with downloadOperation. + */ +- (nonnull instancetype)initWithDownloadOperation:(nullable NSOperation *)downloadOperation; + @end diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index d10184d9..ad4419ea 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -199,8 +199,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; id downloadOperationCancelToken = [operation addHandlersForProgress:progressBlock completed:completedBlock]; - SDWebImageDownloadToken *token = [SDWebImageDownloadToken new]; - token.downloadOperation = operation; + SDWebImageDownloadToken *token = [[SDWebImageDownloadToken alloc] initWithDownloadOperation:operation]; token.url = url; token.request = operation.request; token.downloadOperationCancelToken = downloadOperationCancelToken; @@ -429,20 +428,25 @@ didReceiveResponse:(NSURLResponse *)response @implementation SDWebImageDownloadToken - (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self name:SDWebImageDownloadReceiveResponseNotification object:_downloadOperation]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:SDWebImageDownloadReceiveResponseNotification object:nil]; } -- (void)setDownloadOperation:(NSOperation *)downloadOperation { - if (downloadOperation != _downloadOperation) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:SDWebImageDownloadReceiveResponseNotification object:_downloadOperation]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadReceiveResponse:) name:SDWebImageDownloadReceiveResponseNotification object:downloadOperation]; +- (instancetype)init { + return [self initWithDownloadOperation:nil]; +} + +- (instancetype)initWithDownloadOperation:(NSOperation *)downloadOperation { + self = [super init]; + if (self) { _downloadOperation = downloadOperation; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadReceiveResponse:) name:SDWebImageDownloadReceiveResponseNotification object:downloadOperation]; } + return self; } - (void)downloadReceiveResponse:(NSNotification *)notification { NSOperation *downloadOperation = notification.object; - if (downloadOperation) { + if (downloadOperation && downloadOperation == self.downloadOperation) { self.response = downloadOperation.response; } } From 22a8c43bca2f3c815bf6561d4742e9c2c96b1fe5 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 9 Aug 2018 17:21:24 +0800 Subject: [PATCH 237/361] Put download token init internal --- SDWebImage/SDWebImageDownloader.h | 7 ------- SDWebImage/SDWebImageDownloader.m | 8 ++++---- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index b1d2d120..351d57d1 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -91,8 +91,6 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStopNotification; typedef SDImageLoaderProgressBlock SDWebImageDownloaderProgressBlock; typedef SDImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock; -@protocol SDWebImageDownloaderOperation; - /** * A token associated with each download. Can be used to cancel a download */ @@ -118,11 +116,6 @@ typedef SDImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock; */ @property (nonatomic, strong, nullable, readonly) NSURLResponse *response; -/** - Init download token with downloadOperation. - */ -- (nonnull instancetype)initWithDownloadOperation:(nullable NSOperation *)downloadOperation; - @end diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index ad4419ea..a7eef36e 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -23,6 +23,10 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; @property (nonatomic, weak, nullable) SDWebImageDownloader *downloader; @property (nonatomic, assign, getter=isCancelled) BOOL cancelled; +- (nonnull instancetype)init NS_UNAVAILABLE; ++ (nonnull instancetype)new NS_UNAVAILABLE; +- (nonnull instancetype)initWithDownloadOperation:(nullable NSOperation *)downloadOperation NS_DESIGNATED_INITIALIZER; + @end @interface SDWebImageDownloader () @@ -431,10 +435,6 @@ didReceiveResponse:(NSURLResponse *)response [[NSNotificationCenter defaultCenter] removeObserver:self name:SDWebImageDownloadReceiveResponseNotification object:nil]; } -- (instancetype)init { - return [self initWithDownloadOperation:nil]; -} - - (instancetype)initWithDownloadOperation:(NSOperation *)downloadOperation { self = [super init]; if (self) { From 9a635201157ca52754f70c7198390385f67adff7 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 9 Aug 2018 20:43:35 +0800 Subject: [PATCH 238/361] Remove NS_DESIGNATED_INITIALIZER macro --- SDWebImage/SDWebImageDownloader.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index a7eef36e..ec67b5bd 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -25,7 +25,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; - (nonnull instancetype)init NS_UNAVAILABLE; + (nonnull instancetype)new NS_UNAVAILABLE; -- (nonnull instancetype)initWithDownloadOperation:(nullable NSOperation *)downloadOperation NS_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithDownloadOperation:(nullable NSOperation *)downloadOperation; @end From 3a22bcff583db15adfb649b81dae812202842e0f Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 10 Aug 2018 09:00:34 +0800 Subject: [PATCH 239/361] Fix cache migration when dstPath intermediate directories not exist --- SDWebImage/SDDiskCache.h | 1 + SDWebImage/SDDiskCache.m | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/SDWebImage/SDDiskCache.h b/SDWebImage/SDDiskCache.h index 7860c613..02e42d66 100644 --- a/SDWebImage/SDDiskCache.h +++ b/SDWebImage/SDDiskCache.h @@ -109,6 +109,7 @@ If the old location does not exist, does nothing. If the new location does not exist, only do a movement of directory. If the new location does exist, will move and merge the files from old location. + If the new location does exist, but is not a directory, will remove it and do a movement of directory. @param srcPath old location of cache directory @param dstPath new location of cache directory diff --git a/SDWebImage/SDDiskCache.m b/SDWebImage/SDDiskCache.m index 00612c96..ebf40fcf 100644 --- a/SDWebImage/SDDiskCache.m +++ b/SDWebImage/SDDiskCache.m @@ -246,6 +246,11 @@ // New path is not directory, remove file [self.fileManager removeItemAtPath:dstPath error:nil]; } + NSString *dstParentPath = [dstPath stringByDeletingLastPathComponent]; + // Creates any non-existent parent directories as part of creating the directory in path + if (![self.fileManager fileExistsAtPath:dstParentPath]) { + [self.fileManager createDirectoryAtPath:dstParentPath withIntermediateDirectories:YES attributes:nil error:NULL]; + } // New directory does not exist, rename directory [self.fileManager moveItemAtPath:srcPath toPath:dstPath error:nil]; } else { @@ -253,7 +258,6 @@ NSDirectoryEnumerator *dirEnumerator = [self.fileManager enumeratorAtPath:srcPath]; NSString *file; while ((file = [dirEnumerator nextObject])) { - // Don't handle error, just try to move. [self.fileManager moveItemAtPath:[srcPath stringByAppendingPathComponent:file] toPath:[dstPath stringByAppendingPathComponent:file] error:nil]; } // Remove the old path From 6e79ef51f0ec950f5428770f4d503443bfd95222 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 10 Aug 2018 12:52:31 +0800 Subject: [PATCH 240/361] Fix a race condition during progressive animation load in SDAnimatedImageView. When the coder was updated, currentData may not be the same instance as previousdData. We should check the that current data is appended by previous data --- SDWebImage/SDAnimatedImageView.m | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index ebbffd78..99bebeee 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -621,20 +621,28 @@ static NSUInteger SDDeviceFreeMemory() { return; } if ([image conformsToProtocol:@protocol(SDAnimatedImage)] && image.sd_isIncremental) { - NSData *currentData = [((UIImage *)image) animatedImageData]; - if (currentData) { - NSData *previousData; - if ([self.image conformsToProtocol:@protocol(SDAnimatedImage)]) { - previousData = [((UIImage *)self.image) animatedImageData]; - } - // Check whether to use progressive coding - if (!previousData) { - // If previous data is nil - self.isProgressive = YES; - } else if ([currentData isEqualToData:previousData]) { - // If current data is equal to previous data + UIImage *previousImage = self.image; + if ([previousImage conformsToProtocol:@protocol(SDAnimatedImage)] && previousImage.sd_isIncremental) { + NSData *previousData = [((UIImage *)previousImage) animatedImageData]; + NSData *currentData = [((UIImage *)image) animatedImageData]; + // Check whether to use progressive rendering or not + + // Warning: normally the `previousData` is same instance as `currentData` because our `SDAnimatedImage` class share the same `coder` instance internally. But there may be a race condition, that later retrived `currentData` is already been updated and it's not the same instance as `previousData`. + // And for protocol extensible design, we should not assume `SDAnimatedImage` protocol implementations always share same instance. So both of two reasons, we need that `rangeOfData` check. + if ([currentData isEqualToData:previousData]) { + // If current data is the same data (or instance) as previous data self.isProgressive = YES; + } else if (currentData.length > previousData.length) { + // If current data is appended by previous data, use `NSDataSearchAnchored` + NSRange range = [currentData rangeOfData:previousData options:NSDataSearchAnchored range:NSMakeRange(0, previousData.length)]; + if (range.location == 0 && range.length == previousData.length) { + // Contains hole previous data and they start with the same beginning + self.isProgressive = YES; + } } + } else { + // Previous image is not progressive, so start progressive rendering + self.isProgressive = YES; } } } From fc23b93d08304246b4e710671f7429388521f4a1 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 10 Aug 2018 08:40:23 +0800 Subject: [PATCH 241/361] Update the test about progressive decoding of other image format --- Tests/Tests/SDImageCacheTests.m | 2 +- Tests/Tests/SDTestCase.h | 4 +- Tests/Tests/SDTestCase.m | 4 +- Tests/Tests/SDWebCacheCategoriesTests.m | 16 ++++---- Tests/Tests/SDWebImageDownloaderTests.m | 54 +++++++++++++++++++------ Tests/Tests/SDWebImageManagerTests.m | 6 +-- 6 files changed, 60 insertions(+), 26 deletions(-) diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index 06e71df3..c4784ad0 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -232,7 +232,7 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; } - (void)test34CachePathForSimpleKeyWithExtension { - NSString *cachePath = [[SDImageCache sharedImageCache] cachePathForKey:kTestJpegURL]; + NSString *cachePath = [[SDImageCache sharedImageCache] cachePathForKey:kTestJPEGURL]; expect(cachePath).toNot.beNil(); expect([cachePath pathExtension]).to.equal(@"jpg"); } diff --git a/Tests/Tests/SDTestCase.h b/Tests/Tests/SDTestCase.h index 566381c1..80ddd93c 100644 --- a/Tests/Tests/SDTestCase.h +++ b/Tests/Tests/SDTestCase.h @@ -16,10 +16,12 @@ FOUNDATION_EXPORT const int64_t kAsyncTestTimeout; FOUNDATION_EXPORT const int64_t kMinDelayNanosecond; -FOUNDATION_EXPORT NSString * _Nonnull const kTestJpegURL; +FOUNDATION_EXPORT NSString * _Nonnull const kTestJPEGURL; +FOUNDATION_EXPORT NSString * _Nonnull const kTestProgressiveJPEGURL; FOUNDATION_EXPORT NSString * _Nonnull const kTestPNGURL; FOUNDATION_EXPORT NSString * _Nonnull const kTestGIFURL; FOUNDATION_EXPORT NSString * _Nonnull const kTestWebPURL; +FOUNDATION_EXPORT NSString * _Nonnull const kTestAPNGPURL; @interface SDTestCase : XCTestCase diff --git a/Tests/Tests/SDTestCase.m b/Tests/Tests/SDTestCase.m index fbdb2945..0851c8fb 100644 --- a/Tests/Tests/SDTestCase.m +++ b/Tests/Tests/SDTestCase.m @@ -11,10 +11,12 @@ const int64_t kAsyncTestTimeout = 5; const int64_t kMinDelayNanosecond = NSEC_PER_MSEC * 100; // 0.1s -NSString *const kTestJpegURL = @"http://via.placeholder.com/50x50.jpg"; +NSString *const kTestJPEGURL = @"http://via.placeholder.com/50x50.jpg"; +NSString *const kTestProgressiveJPEGURL = @"https://raw.githubusercontent.com/ibireme/YYImage/master/Demo/YYImageDemo/mew_progressive.jpg"; NSString *const kTestPNGURL = @"http://via.placeholder.com/50x50.png"; NSString *const kTestGIFURL = @"https://media.giphy.com/media/UEsrLdv7ugRTq/giphy.gif"; NSString *const kTestWebPURL = @"http://littlesvr.ca/apng/images/SteamEngine.webp"; +NSString *const kTestAPNGPURL = @"https:raw.githubusercontent.com/onevcat/APNGKit/master/TestImages/APNG-cube.apng"; @implementation SDTestCase diff --git a/Tests/Tests/SDWebCacheCategoriesTests.m b/Tests/Tests/SDWebCacheCategoriesTests.m index eedca13b..7a02a534 100644 --- a/Tests/Tests/SDWebCacheCategoriesTests.m +++ b/Tests/Tests/SDWebCacheCategoriesTests.m @@ -20,7 +20,7 @@ XCTestExpectation *expectation = [self expectationWithDescription:@"UIImageView setImageWithURL"]; UIImageView *imageView = [[UIImageView alloc] init]; - NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL]; [imageView sd_setImageWithURL:originalImageURL completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { expect(image).toNot.beNil(); @@ -37,7 +37,7 @@ XCTestExpectation *expectation = [self expectationWithDescription:@"UIImageView setHighlightedImageWithURL"]; UIImageView *imageView = [[UIImageView alloc] init]; - NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL]; [imageView sd_setHighlightedImageWithURL:originalImageURL completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { expect(image).toNot.beNil(); @@ -54,7 +54,7 @@ XCTestExpectation *expectation = [self expectationWithDescription:@"MKAnnotationView setImageWithURL"]; MKAnnotationView *annotationView = [[MKAnnotationView alloc] init]; - NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL]; [annotationView sd_setImageWithURL:originalImageURL completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { expect(image).toNot.beNil(); @@ -71,7 +71,7 @@ XCTestExpectation *expectation = [self expectationWithDescription:@"UIButton setImageWithURL normalState"]; UIButton *button = [[UIButton alloc] init]; - NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL]; [button sd_setImageWithURL:originalImageURL forState:UIControlStateNormal completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { @@ -88,7 +88,7 @@ XCTestExpectation *expectation = [self expectationWithDescription:@"UIButton setImageWithURL highlightedState"]; UIButton *button = [[UIButton alloc] init]; - NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL]; [button sd_setImageWithURL:originalImageURL forState:UIControlStateHighlighted completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { @@ -105,7 +105,7 @@ XCTestExpectation *expectation = [self expectationWithDescription:@"UIButton setBackgroundImageWithURL normalState"]; UIButton *button = [[UIButton alloc] init]; - NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL]; [button sd_setBackgroundImageWithURL:originalImageURL forState:UIControlStateNormal completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { @@ -122,7 +122,7 @@ - (void)testUIViewImageProgressKVOWork { XCTestExpectation *expectation = [self expectationWithDescription:@"UIView imageProgressKVO failed"]; UIView *view = [[UIView alloc] init]; - NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL]; [self.KVOController observe:view.sd_imageProgress keyPath:NSStringFromSelector(@selector(fractionCompleted)) options:NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionary * _Nonnull change) { NSProgress *progress = object; @@ -133,7 +133,7 @@ }]; // Clear the disk cache to force download from network - [[SDImageCache sharedImageCache] removeImageForKey:kTestJpegURL withCompletion:^{ + [[SDImageCache sharedImageCache] removeImageForKey:kTestJPEGURL withCompletion:^{ [view sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 context:nil setImageBlock:nil progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { expect(view.sd_imageProgress.fractionCompleted).equal(1.0); expect([view.sd_imageProgress.userInfo[NSStringFromSelector(_cmd)] boolValue]).equal(YES); diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index d668e1a2..531bc20a 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -53,7 +53,7 @@ - (void)test04ThatASimpleDownloadWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Simple download"]; - NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { if (image && data && !error && finished) { [expectation fulfill]; @@ -75,7 +75,7 @@ - (void)test06ThatUsingACustomDownloaderOperationWorks { SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] initWithConfig:nil]; - NSURL *imageURL1 = [NSURL URLWithString:kTestJpegURL]; + NSURL *imageURL1 = [NSURL URLWithString:kTestJPEGURL]; NSURL *imageURL2 = [NSURL URLWithString:kTestPNGURL]; NSURL *imageURL3 = [NSURL URLWithString:kTestGIFURL]; // we try to set a usual NSOperation as operation class. Should not work @@ -131,7 +131,7 @@ - (void)test09ThatProgressiveJPEGWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Progressive JPEG download"]; - NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *imageURL = [NSURL URLWithString:kTestProgressiveJPEGURL]; [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:SDWebImageDownloaderProgressiveLoad progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { if (image && data && !error && finished) { [expectation fulfill]; @@ -161,7 +161,7 @@ - (void)test11ThatCancelWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Cancel"]; - NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; SDWebImageDownloadToken *token = [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { XCTFail(@"Should not get here"); @@ -181,7 +181,7 @@ - (void)test12ThatWeCanUseAnotherSessionForEachDownloadOperation { XCTestExpectation *expectation = [self expectationWithDescription:@"Owned session"]; - NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:imageURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15]; request.HTTPShouldUsePipelining = YES; @@ -207,7 +207,7 @@ - (void)test13ThatDownloadCanContinueWhenTheAppEntersBackground { XCTestExpectation *expectation = [self expectationWithDescription:@"Simple download"]; - NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:SDWebImageDownloaderContinueInBackground progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { if (image && data && !error && finished) { [expectation fulfill]; @@ -287,6 +287,36 @@ }]; } +- (void)test18ThatProgressiveGIFWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Progressive GIF download"]; + NSURL *imageURL = [NSURL URLWithString:kTestGIFURL]; + [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:SDWebImageDownloaderProgressiveLoad progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + if (image && data && !error && finished) { + [expectation fulfill]; + } else if (finished) { + XCTFail(@"Something went wrong"); + } else { + // progressive updates + } + }]; + [self waitForExpectationsWithCommonTimeout]; +} + +- (void)test19ThatProgressiveAPNGWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Progressive APNG download"]; + NSURL *imageURL = [NSURL URLWithString:kTestAPNGPURL]; + [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:SDWebImageDownloaderProgressiveLoad progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + if (image && data && !error && finished) { + [expectation fulfill]; + } else if (finished) { + XCTFail(@"Something went wrong"); + } else { + // progressive updates + } + }]; + [self waitForExpectationsWithCommonTimeout]; +} + /** * Per #883 - Fix multiple requests for same image and then canceling one * Old SDWebImage (3.x) could not handle correctly multiple requests for the same image + cancel @@ -296,7 +326,7 @@ - (void)test20ThatDownloadingSameURLTwiceAndCancellingFirstWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Correct image downloads"]; - NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; SDWebImageDownloadToken *token1 = [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL @@ -334,7 +364,7 @@ - (void)test21ThatCancelingDownloadThenRequestingAgainWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Correct image downloads"]; - NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; SDWebImageDownloadToken *token1 = [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL @@ -403,7 +433,7 @@ components.query = @"text=Hello+World"; mutableRequest.URL = components.URL; return mutableRequest; - } else if ([request.URL.absoluteString isEqualToString:kTestJpegURL]) { + } else if ([request.URL.absoluteString isEqualToString:kTestJPEGURL]) { // Test that return nil request will treat as error return nil; } else { @@ -415,7 +445,7 @@ __block BOOL firstCheck = NO; __block BOOL secondCheck = NO; - [downloader downloadImageWithURL:[NSURL URLWithString:kTestJpegURL] options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + [downloader downloadImageWithURL:[NSURL URLWithString:kTestJPEGURL] options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { // Except error expect(error).notTo.beNil(); firstCheck = YES; @@ -440,7 +470,7 @@ - (void)test30CustomImageLoaderWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Custom image not works"]; SDWebImageTestLoader *loader = [[SDWebImageTestLoader alloc] init]; - NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; [loader loadImageWithURL:imageURL options:0 context:nil progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { expect(targetURL).notTo.beNil(); } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { @@ -454,7 +484,7 @@ - (void)test31ThatLoadersManagerWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Loaders manager not works"]; - NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; [[SDImageLoadersManager sharedManager] loadImageWithURL:imageURL options:0 context:nil progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { expect(targetURL).notTo.beNil(); } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { diff --git a/Tests/Tests/SDWebImageManagerTests.m b/Tests/Tests/SDWebImageManagerTests.m index ef4be045..48916c7e 100644 --- a/Tests/Tests/SDWebImageManagerTests.m +++ b/Tests/Tests/SDWebImageManagerTests.m @@ -23,7 +23,7 @@ - (void)test02ThatDownloadInvokesCompletionBlockWithCorrectParamsAsync { __block XCTestExpectation *expectation = [self expectationWithDescription:@"Image download completes"]; - NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL]; [[SDWebImageManager sharedManager] loadImageWithURL:originalImageURL options:SDWebImageRefreshCached @@ -111,14 +111,14 @@ - (void)test08ThatImageTransformerWork { XCTestExpectation *expectation = [self expectationWithDescription:@"Image transformer work"]; - NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; + NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; SDWebImageTestTransformer *transformer = [[SDWebImageTestTransformer alloc] init]; NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; NSString *testImagePath = [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; transformer.testImage = [[UIImage alloc] initWithContentsOfFile:testImagePath]; SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:[SDImageCache sharedImageCache] loader:[SDWebImageDownloader sharedDownloader]]; manager.transformer = transformer; - [[SDImageCache sharedImageCache] removeImageForKey:kTestJpegURL withCompletion:^{ + [[SDImageCache sharedImageCache] removeImageForKey:kTestJPEGURL withCompletion:^{ [manager loadImageWithURL:imageURL options:SDWebImageTransformAnimatedImage progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { expect(image).equal(transformer.testImage); [expectation fulfill]; From 8bd5e5e44d93b5bdfbad22bd7a6f7c184f551eb6 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 10 Aug 2018 09:49:40 +0800 Subject: [PATCH 242/361] Add more tests for animated coder --- Tests/Tests/SDAnimatedImageTest.m | 36 ++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index 43e19d58..fa505871 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -102,7 +102,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun expect(imageView.currentFrame).beNil(); // current frame } -- (void)test07AnimatedImageViewSetAnimatedImage { +- (void)test07AnimatedImageViewSetAnimatedImageWEBP { SDAnimatedImageView *imageView = [SDAnimatedImageView new]; SDAnimatedImage *image = [SDAnimatedImage imageWithData:[self testAnimatedWebPData]]; imageView.image = image; @@ -110,7 +110,23 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun expect(imageView.currentFrame).notTo.beNil(); // current frame } -- (void)test08AnimatedImageViewRendering { +- (void)test08AnimatedImageViewSetAnimatedImageGIF { + SDAnimatedImageView *imageView = [SDAnimatedImageView new]; + SDAnimatedImage *image = [SDAnimatedImage imageWithData:[self testGIFData]]; + imageView.image = image; + expect(imageView.image).notTo.beNil(); + expect(imageView.currentFrame).notTo.beNil(); // current frame +} + +- (void)test09AnimatedImageViewSetAnimatedImageAPNG { + SDAnimatedImageView *imageView = [SDAnimatedImageView new]; + SDAnimatedImage *image = [SDAnimatedImage imageWithData:[self testAPNGPData]]; + imageView.image = image; + expect(imageView.image).notTo.beNil(); + expect(imageView.currentFrame).notTo.beNil(); // current frame +} + +- (void)test10AnimatedImageViewRendering { XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView rendering"]; SDAnimatedImageView *imageView = [[SDAnimatedImageView alloc] init]; #if SD_UIKIT @@ -152,7 +168,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun [self waitForExpectationsWithCommonTimeout]; } -- (void)test09AnimatedImageViewSetProgressiveAnimatedImage { +- (void)test11AnimatedImageViewSetProgressiveAnimatedImage { NSData *gifData = [self testGIFData]; SDImageGIFCoder *progressiveCoder = [[SDImageGIFCoder alloc] initIncrementalWithOptions:nil]; // simulate progressive decode, pass partial data @@ -179,7 +195,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun expect(isProgressive).equal(NO); } -- (void)test10AnimatedImageViewCategory { +- (void)test12AnimatedImageViewCategory { XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"]; SDAnimatedImageView *imageView = [SDAnimatedImageView new]; NSURL *testURL = [NSURL URLWithString:kTestWebPURL]; @@ -192,7 +208,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun [self waitForExpectationsWithCommonTimeout]; } -- (void)test11AnimatedImageViewCategoryProgressive { +- (void)test13AnimatedImageViewCategoryProgressive { XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"]; SDAnimatedImageView *imageView = [SDAnimatedImageView new]; NSURL *testURL = [NSURL URLWithString:kTestGIFURL]; @@ -249,6 +265,16 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun return [NSData dataWithContentsOfFile:[self testAnimatedWebPPath]]; } +- (NSString *)testAPNGPPath { + NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; + NSString *testPath = [testBundle pathForResource:@"TestImageAnimated" ofType:@"apng"]; + return testPath; +} + +- (NSData *)testAPNGPData { + return [NSData dataWithContentsOfFile:[self testAPNGPPath]]; +} + - (NSString *)testJPEGPath { NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; NSString *testPath = [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; From b0775361b5e4416628ddc257ca3e2b0318e103bb Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 10 Aug 2018 10:19:21 +0800 Subject: [PATCH 243/361] Add more test about SDAnimatedImage --- Tests/Tests/SDAnimatedImageTest.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index fa505871..af953100 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -218,6 +218,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun // Progressive image may be nil when download data is not enough if (image) { expect(image.sd_isIncremental).beTruthy(); + expect([image conformsToProtocol:@protocol(SDAnimatedImage)]).beTruthy(); BOOL isProgressive = imageView.isProgressive; expect(isProgressive).equal(YES); } From 7187aff159ec8f9d728299c4ee605c206be4a53a Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 10 Aug 2018 14:50:25 +0800 Subject: [PATCH 244/361] Update SDAnimatedImage test and HEIC/HEIF test --- .../project.pbxproj | 12 +++++ Tests/Tests/Images/TestImage.heic | Bin 0 -> 169189 bytes Tests/Tests/Images/TestImage.heif | Bin 0 -> 134911 bytes Tests/Tests/SDAnimatedImageTest.m | 25 +++++++-- Tests/Tests/SDImageCoderTests.m | 49 ++++++++++++++---- Tests/Tests/SDTestCase.m | 2 +- 6 files changed, 72 insertions(+), 16 deletions(-) create mode 100644 Tests/Tests/Images/TestImage.heic create mode 100644 Tests/Tests/Images/TestImage.heif diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 51eda380..46b738cd 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -23,8 +23,12 @@ 3264FF30205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */; }; 327054E2206CEFF3006EA328 /* TestImageAnimated.apng in Resources */ = {isa = PBXBuildFile; fileRef = 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */; }; 327054E3206CEFF3006EA328 /* TestImageAnimated.apng in Resources */ = {isa = PBXBuildFile; fileRef = 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */; }; + 327A418C211D660600495442 /* TestImage.heic in Resources */ = {isa = PBXBuildFile; fileRef = 327A418B211D660600495442 /* TestImage.heic */; }; + 327A418D211D660600495442 /* TestImage.heic in Resources */ = {isa = PBXBuildFile; fileRef = 327A418B211D660600495442 /* TestImage.heic */; }; 328BB6DD20825E9800760D6C /* SDWebImageTestCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6DC20825E9800760D6C /* SDWebImageTestCache.m */; }; 328BB6DE20825E9800760D6C /* SDWebImageTestCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6DC20825E9800760D6C /* SDWebImageTestCache.m */; }; + 32905E64211D786E00460FCF /* TestImage.heif in Resources */ = {isa = PBXBuildFile; fileRef = 32905E63211D786E00460FCF /* TestImage.heif */; }; + 32905E65211D786E00460FCF /* TestImage.heif in Resources */ = {isa = PBXBuildFile; fileRef = 32905E63211D786E00460FCF /* TestImage.heif */; }; 32A571562037DB2D002EDAAE /* SDAnimatedImageTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */; }; 32B99E8B203AF8690017FD66 /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */; }; 32B99E9B203B2EDD0017FD66 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; }; @@ -78,8 +82,10 @@ 3264FF2D205D42CB00F6BD48 /* SDWebImageTestTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestTransformer.h; sourceTree = ""; }; 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestTransformer.m; sourceTree = ""; }; 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageAnimated.apng; sourceTree = ""; }; + 327A418B211D660600495442 /* TestImage.heic */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImage.heic; sourceTree = ""; }; 328BB6DB20825E9800760D6C /* SDWebImageTestCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestCache.h; sourceTree = ""; }; 328BB6DC20825E9800760D6C /* SDWebImageTestCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestCache.m; sourceTree = ""; }; + 32905E63211D786E00460FCF /* TestImage.heif */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImage.heif; sourceTree = ""; }; 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImageTest.m; sourceTree = ""; }; 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDCategoriesTests.m; sourceTree = ""; }; 32B99E92203B2DF90017FD66 /* Tests Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -151,6 +157,8 @@ 5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */, 43828A441DA67F9900000E62 /* TestImageLarge.jpg */, 433BBBB81D7EF8260086B6E9 /* TestImage.png */, + 327A418B211D660600495442 /* TestImage.heic */, + 32905E63211D786E00460FCF /* TestImage.heif */, 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */, 321259EB1F39E3240096FE0E /* TestImageStatic.webp */, 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */, @@ -326,6 +334,8 @@ 32B99EA4203B31360017FD66 /* TestImage.jpg in Resources */, 32B99EA6203B31360017FD66 /* TestImage.png in Resources */, 32B99EA2203B31360017FD66 /* MonochromeTestImage.jpg in Resources */, + 32905E65211D786E00460FCF /* TestImage.heif in Resources */, + 327A418D211D660600495442 /* TestImage.heic in Resources */, 32B99EA8203B31360017FD66 /* TestImageStatic.webp in Resources */, 32B99EA7203B31360017FD66 /* TestImageAnimated.webp in Resources */, 32B99EA5203B31360017FD66 /* TestImageLarge.jpg in Resources */, @@ -336,8 +346,10 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 327A418C211D660600495442 /* TestImage.heic in Resources */, 321259EE1F39E4110096FE0E /* TestImageAnimated.webp in Resources */, 5F7F38AD1AE2A77A00B0E330 /* TestImage.jpg in Resources */, + 32905E64211D786E00460FCF /* TestImage.heif in Resources */, 43828A451DA67F9900000E62 /* TestImageLarge.jpg in Resources */, 433BBBB71D7EF8200086B6E9 /* TestImage.gif in Resources */, 321259EC1F39E3240096FE0E /* TestImageStatic.webp in Resources */, diff --git a/Tests/Tests/Images/TestImage.heic b/Tests/Tests/Images/TestImage.heic new file mode 100644 index 0000000000000000000000000000000000000000..f0bfa227019b891a26a5e74a0007dbf28c964782 GIT binary patch literal 169189 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 C6p=Up literal 0 HcmV?d00001 diff --git a/Tests/Tests/Images/TestImage.heif b/Tests/Tests/Images/TestImage.heif new file mode 100644 index 0000000000000000000000000000000000000000..b16f92bb57eaa7ffc952160feaf535f61d68f85d GIT binary patch literal 134911 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á`UvC4rX1RQR4%Hbx2<%Kmt%X z{)xW^<%;slfo>te!k4Y=zCYpCG~N%cOQkk%b^)8Q3z>Bc3Pdncx!V0_^NDzl!wyU= z_1cD6!fVShi?E}b2JIQ-3DjAP8LjI`n0a}nFtZx3GaUD_Nh*b4Mm~5tH_t3n9pCl0 zT%Enjzn;vjXUl9bl18=oso)*+Xuo?uO5+@m8`J`-fSHt^o;HR>u;w2C%0o>g!oCsm zrJ9~%H#D|9%J{^;7w0KX0C+)jM4kWzAzwJ;vEY^ET$%6xshO6XyWd!N_>*DKw1?`Y zbXnQc7hs7SlP71#Wy2#JK3dPC-b&KiO(~>a>$qmY?;Ws00aV;c>SC&V6E8Tn3s145 zu{xk$V(gSETl`3aGYxEE=yM|xJ5lH=+*5`UN{`wEOgO`jgeiC9UEUx<8FqdhqKjkY(rCCPIk*P}h#?L90DZ5I6$1Xt3NhsuV zZ|&|iW2U2vo|HAdu}93agkXxFz&z2w9_|JZgEwDFHst(F6;&ioyNj8_!jUjaxkTAH zZ|fWT=1B>E28?tFMQ+-C{M&=8*01=lD;69>UGjNlQK@adUDH>tMeG4Gj9}G=Nv2_c zkn;EPU3|iey9C_l_qBM^!a&|$-N<81&3BbDCLsg3wqibx6Kk||0KH(`%iGzt!R3h! zr7i~?wz9efpC5);<(p`MnUDW~cX9D_=7C{P-bh$uklYV-Rj`$2iI(%B!1KQ{ zLe2mG`c@itP6Fm=XzQ8fwhfsASOu7Il zcBQ{|g;XYLXrg)(p(@d$`L3f6cXCBUu?wp((s=emrqY*#7!}9z^@VUWXSeMT2lmnm zhsxlEDmk#vsKa?V02Rp$U;|G zpT72=yiLpMUqD_!_IYP>tBLvt%ZDQG>KwC_0GXC@3_+~S19|c*_G=>{3{lxJC@H}n z{%fum%!qy2TL2lneh_-GrA0TEaqs!v(vRWaHYH|Du@G&L0W@kJuR69%6JY*EBqQyx zZ+vf*>idU``G-2bu=4CvPWu4wa@iLYgmNuH&F+KfLu%kvl>rlO3` z!n9}QV*J)}$_ZgTWaNT}W`y9_K%hhfeE0I7xLNKY!#e<1$BEy|inHuj={WwWX||eI zVH;hDc6)qmiG#$?uRF2wFsM89E!bxTBO;mKaMAjfBvv3_ATLOyL~c^W(?R^5`M(T} zkMpR+aN~aCM#~<`X}p`V1wT7lMR)8@MMKp#?dZuH-n@beXVI@fr0Vf~Cg{w~WO2pa zoe4dkXd5(VFuQsr4G1P1k_In#ws3Z|`#qRmKqd(n0bw z5k^-E1$Mww<+_kNND9}>5)DC~GpmgcqU3^b@GlwqYwQ?>e;1%z>{ap6Y&W!lN-=Z@ zS5_Q6ZQT*m%zk!~C#9`}ALGk5F*dA!zD!d~#k0im&Z8=}b`n%=IKUsf!8ZT<{jrU+z zUk#gzcfxr!=XDpna`RsaJ*hp0_Kt!ZCHi_Lz}g5+AA?OHCLcQF>2T`6c0O&_H(D3g zFg=c9%`oCh8(AJFH}N*_^JhThe~i6+S4meoD5Ni7Q3Zn_K+IzmRRdrE&jlP3V=lWn zi<`<#o$fb%7g~w9ALZ$pn~vSj6!ZVNXq?!+vP*?2jaEXmziBy&a|NQndK)?1dTDPB z*CtleCMH6r?rB9Ct0F}-M~=3#@Rk4PwP4yi_qj*i-dAyC+=w16HOh@eyHQuxz{#Cyx>lZY&+566ej z@3QGbkuS_3i6n+^5gNWz{k$P!Tw{KGx@RcZRy%Y>^=*Vw>tw)Lf~kA4ya3;*7mT?r2FTsmXe zY8Xl|5z|36p)SUo38OMuf5~?}l+7=-733t0sp61F78HVS4Vg{}q~G2uc0_%%lL#|= z=}0{6(d0jEFfx@mlkj)d_ zc}Tx-YarPMXBgO#&+m-)w-EabDnWfe3s`x2{f9o=#&*=NDXq$i}qJQ^3D;BYKs*GLr$@+_4CC$~zhvo^#iXhUT&vZfK< zo4zOGnVzUWphFI6BsN9u(*51-nNZwX8@Oau$ zP*UW3{K(H$3C1xH9g`Y0#d7t9enI{l)#HLFsR4?EDQH3~De|Ms1(Pq9D&kwbRwLx^#Va?8YcU>J zW9y=l*cC5T_k8nCzntWrT!U2Rq-6)B8=ltkb_ZIYeZuFCA@>azXMI(=O` znn_i{Cn2_u3S9dU;(6g&kee&reZb*r6A~=iWmv8P4-UU0Y^;LJs4Ig(HOP8gKHfV& zTMf5cBduorDp^6|^@q;W$*!wBtfM&Yaj|WBSRAUK#p+`CBV0keT>Ee`Ya!bmT`7OA zmNx|yfbu2u8+2^Sus?3zuPlb7s@19S8ct3{2@n(eW)#hwieG30_fP}1r#3;+85Qrh zwemi`Ck2tYKZD*e!>pKZxkblE;l%4ihzXCaWho?#|8=Hw--D&c6S%m{x1MTZ z?-<@NVSD8h4BiMhM|C47l^^u%X5sC`@tBwWbaWaE`rWAZ)y>{g@?pqX7`@x}^tg=# z#+?6p@KTnuHiSJsR<;djNSBqJF* zcId7%=ScYtUFy78z^D)jaCqwb@6ytA$Hq$+<-7~*xGy`Jgn3H@suT+CK>+G7P#D50 z>>mdV%rAB3M6MDJ!&V-$DYA(fQ$tKfiH}_mhN~_Kun-al&mY zRWE5jc9PhHDb$jl2ovwPmNE*0nu;yNt?K8_o8AiSc+We%`UnxPt96jMc0L2hx%9sQ zd2q4upgt;d7$Uj+t)%+GLV_Irwhh!*z|044NS=E{gfXi||bKKX~|+6nA* z2SxTHB*mrl?&mpK8-0*x9Tnd=48$w$OVWh$VYe#fk96vR+yL|Z+<6)wVU5KnYCg&+ zBJD8Nc+Fm9w^ODYLfNJ*g2^|8;#U5AzsW(o* zt86pj>hMoVr2q1D=J8R37h8csjjL*IT6Ia(>{#8lQW>F&#K-D;Pi@s$S(At{ld%X; zbb2G~$AUP)`}OH9-)4yQYaqS+7&#y%3V@+}Ei+I0dPIfQk?3sI&Mm+#6dDveJctf>LG@hFUQgD10PKsrwc_@k0_<{TdDs`|O_KX!(zG zet6{`%LlowB0nfA@PR!#C8Dr&gmRnA?#wI#-UM9+#8%id?M9R3eVxHY;)8P z>=TT4*XdK(`&1M`>4V=uF6m@!sTCA9KE#$dr#>OyLOM#VscJ~9s31uSZ8NM9si;8@G0mc`#ov_|GvcqO7nw2Wq6p0zd~;}j+g$0Ro&+4BC}lUm;?e|=j^Ew zs(Y&k!i@rIFDjQ&_?vr|2~iVViqCB=VcdXRgi#f^v*E&+iW+bJ>fSk1KSlq*T#2)w zeg5?^JvBjR`xj7nL;@dfx^zW6HT-CYKTMIUp_rz4TNUN-^7ElPX;-_O5IeQQh}RoM zg}yDxc@V4dLH5>v5@1touABIWiY+(pxuVF=Z?hQhM~U0^`Kq`E?(Lzi3@-D*G~o;l za0i+Sc@=Is%_}SlLAI;z{Qg~~KnN2@?Vxx=)1^+0b}n-pDnAq)W0-*Oo(ZHFnL!ZT zLF5&7>;P-srlpNax-#yBx}_*8RWEN^+0=m#S5Fv?7Ji7+MgDB711x}Mp+VlKKek%$ zoc1%8VgPm%vAr;+oNoZl7uzf_tL9xD`QLulGTTFXdL!byIB;{4z63m8llY-0tA>)t z-s)FfT%tTQ)@;C^a?Z1o5|c1zFx8;WwSYC>Jb`3(-1;wDY;~BjYn}(=aQD*S zQEJWH73*~g8z)FUzg~{FU}fGn81FDPLeAsQ$aU~z2r3?n|A)Q)f7P@}KHeB4a{13# zUOoU#c^U#?NYYi7-F?>Q9DorX=^{Js#GVK9!w8zC>8`eD0{nzBUpYUPd?@tlQ*85LT0cK zpEKtQg|6mNa+u{zJji#xHJJP1S4$oE=GDCqnX>nFDb0i{fA(1!%&hbv>*pD2g?z<{ zceLS#RyU{r5GH)A+%`KCTzG4#MbeOFhi7|~><4IrP==ifX7!RSaGIS&k_a6<^Um>f zyGkti^CR6``rJCX3%VLBuR)?4siFd%;DZ~KJaGx!_M!D1RlZvK!(N5H8EIbq%hjw( zd1s-j<%Z&a)M_{6EK6CKMpAG-p+e`p=zFFtahl~0K^D?Qa84+il5`IPl>Qtr#}B`^ zYW1%fSgsYeD4k<=tp~Puo0i6+Lx2RH8(NSW35QUYhGs6nqqDV%g`0fcuqeX>y41(6 zs_?6NVEDi)P}wOw!-(Z~9gBLV0O}Iu;VgBrr;2jN7Ad$5mLw#$& zjhtFyyr9JTsM}s0yMPHQlKR@bMCgeGX1q$Q3DBoq;vFqkf36I z7g%Q>^B}jy$&p+q(qLF`WJo=n2{1#}6_%HEbQIh+`b(CD{*_;yOn0n;x)h#JEssX1 z7|4C&x35oYG8yHao8&pp?NF3)ZawL)@udtwvDV&TFjYh~Q-LCK{(XR~eF?FJf& zeSxF?MGR6i12u+uI-Pn?IGqo`IM8X{Q0E}}*7c)35y{XLv{z8n<$61AD(-qS!DvIQ z^4K>9%-E;fL=M~#rS!M1Ag*4|V&%C!BM-k6Qp0qjQH%M|v z@PcagVGTJrdTtw{?6H}7#@zqAhYu_Ieq zaf~qL;0TAXl{xxn674)ZmDtxVv%(MOQvvWFu_-t^kPms{7e0jp!#FS z%cr}S`0`{^fb}brUT|tJmD^<};WT%1 zaGBqscb5k<*`bgviq)$|_ZM0|BmheyDqmLzvPz9ivAo@0rsMy4Wc7uf zlT#@x3gp?gN48)-TGNFtiG2mxRU)G*T$D=-v++y0ic+(3YTK+PJlVbN8FCuNc4#mW z*A13nVTZ=i9w(-ARO+ft%{{a{M#zzcibf?IK7#Y0JF&(56 zsA#f|YNS@qtD4+>us5_yZ~YJ@G_CBNtJ~v=O+esUW2C*>wxmH+nUi%@N8s55Pg1j6 zNTJSb&Iyp9Ie1uJS}|@y7$JnrnSx`5PPe3Uofb5R5VX64mj6B$$dnjO?JOGjU5D<~ z2QB%1X4dO~e{!adH-Oz1E1V&y0knWrs>6Or$ODaius0s94&#*v9xR+C;A-e7nq)aN zdGV^*ts5uN6%BSQ z%Kf6F@uZj6OsUC)UCu3dyo0sj;Lo>*TwY_3!5Zh16A(*uzPv=;Jc>#X8WkO<|LTaNADn zcDJULjX9wQ^%(W|pAbx(w`)9XUSfEF?m0MWe3^0U>|ymc;c!8e8|N^7s~)LEv98)E zu(HESvFh_9HnA8-HiPxdN;1!tyw=t&-Cv_-HURE9*=UfKBl(?$HwDshi(s&S>eu~Z zNUIx~gd~>iFK_WxRS5em7F6RZOGX9RS?Tpjp!#ZHvzO2q2h$neYrb;=wK-U%(q@F` zKDx0y0$2GY#0`ReKeY{G2<^FRdopsYS}qdM`se0se+JA?;H03|>XUl5^7|!y^qM|A z_T&n_-tW@KH|NSd%Xx{P_xrL!t5xiea&cWw4ds?PU=++_srA1T@vY&g<8CtPx}XD5sa}AmU4dcD-ZJ+cfp440ftjldHC##{z>eVXwtA(KkMbZhjQst@c(5AUzKaQ= zytBY9;mTfBJ%hCrvh2tRJtB~|-9xeChg0%EU@QZ6DWC&*N>R#~ibXQ)#h#JV2sQv? zB5FZ}9fJgaBvU3(N$@ALhFK!@#4SO3RA9!7RbWwul5x9;TMownwLKbO^a80^|4rW_ zO`OU3?}IK23xJ#B)c^QJgnlgLFb6ACoyQ04L!&Gr{{HYm+V3#S_|VBzyqZzi9xWGR zD(UpzHLhGdV{=>ine-1FUVo9$T6+7vkXIY*-1%6+HX49DJEH~@AOAa+SCFhsN6dE) zz58#^(?XCjjY7%cXbXi9Z{6~x7j))93d$Sj0vvu2V;QhcBkdqol2{%?g?FIw+IsGs zBk@udOwBN7`@f{9ANuO~s1DB2WAev~cqh4jD(||%YsI`6qF%1f6Q5moV-65mFMn*(PlaMb+>k(uZTHxD9w_nPi!8@kQY_HG#W$U_7 zWeUU(C{;c&YbYN|`v8~+dVQrXDabhVI}2e4EG%bBUzvGi&cJ2Y>Y(VWuVo4Gcdw*d z5(;LLZPz*G*LoG2>8OA`MRLH(zNpNs-5R!wCMDQ zVplO=mFun0XVRW7TO-$pI$MX6-riV1ANax}NhT}H|LJ|Hr?IvWt!N-7trEW-xlN)@ zKCcYG!A|=vKk*J!nI}It)ejNVS#W&(*;GiJTWF#SZctgm`=F5?s8Ks+dR^gE^PGQ5 zcgkX5jzbOAHgvzP<`G@&(F?VOJpNxqtoNeA%kpI8lP$2v%(Q$c+I`&8EAJ01ZGU>z z8;~d2D?;R-_u)nMqDTD@SI|^-hS)s1yuN?g3u|~R>Aqd7I;Tl2h9hT(t~TmNh`pLw zR7)hClsaViv{?YvJR!SdN}DQT(6X8h|L;e3XSs3H zoZ7r2xG;D1HOen4(iwyAY|eY;$Egt(KdMgysg|o(89-%-(`4lmS4B|YH`6COJ%R=^ zfN7mEqZ8v*nr3wte}@YU^jNcDpB0-<2R?dktlQwcGYlB~s5UPrBj@18V_xyD-Nnql zhc;mgXxM}`w@bJjk-FWH1q`;Re(5ato7>wb$eXpjQ3;RlrPEBD%vu=Za?=UxyN>E~ zo&ti;n(YQD7qBjow#bRlZt=*+-L*!fZcE-;0VYXjdlkk7FtGC8)&7KpW7&PZ8&DQ5 z!Ytr4F89eop2JvHchP{D&E!X1&g2)jE%nwaPE_>Uthgx(@M zxTA@2UfF)8t-VC1ihl8_GmTZ^A`r`nZ;A3(ZJ!G7crqt|fRW1xD6-PnR1?$9hWb)a zi0Hr*ZTGVhLRiGAv-vV&qE?;L7NtbQ11E)FK8j=4zFww)jgM4nNeAQHX)qaml-`Hu z^*12CFRjh#E3H&pLGz2yItsoutb)&B!98A80cQ!Z%(MB4S67LQRW~dp@eV=!kl*F<5|9Tn`x%@Ybr9Ue4X+$_!Hrz zW4NS7J$-fXO`}7-^j2Y2d3f#OtjscPD2)gLj4DDUv=7oJ&qg&CnLU|L`Z%S4uo79G*rW1 ziZ7DqRamUAx@1Y=r8Wg-Mort4CH@N~9A0DMLqk0I7vz1G;9G>%&ez&&|CHEOLa{n~ z2n@a4_)k3E0>Z~Nn-HNIoKB~OYSKzNzs$UUQkDBSJO}`TyTwDX6 z%nFr;{yuU?HA6WtrZ@~AYTFUU2mWgbs)Br;UpAjQj5zP$+L3cO;lWGgnjj8|iGI!~ zqpC>?6*B5I>t4by*QCTCTDYDYpumcvo_vohX9z< zBxLuu)Q`WOkxd9RZLzto#6p({nxpU=PeypWz5?#S|4ohLDeC7TD`RD*BUP$9QbsWxtuu7BjvpbYpmfg4Hd4sTanRTo21&+dkN@PqX z@m?|fR3>t^A}$7F9W--ox~Qidg$T1a?od-1PRE!yO=C|U5)@ZoGAOS3@aL9~7G|hILfbvAK5mKKdy)kRw@Ay$Hw?wKk;w8_U{V zm788lgi%r$DcN~Y$S{ROU+2t~gjgdd-;J|_v^j}JCDe`zH&4~K^11h3uaQmN3j82Y z#5QbbJj)8nSl;TUTgECi8yL|5xOT3P+o}q$z1UgOM6P3zc*RyC&B-sa>;d}0vXXrR zQcI$jgoPy*JsPz`Yvc**C%oWyU4%s6X#253McgfZrdhoTFIje&SSfOJ#bIuuTd`A( ztOi*)5tT3>V8q+X4+mla#_sB^gJ*30P28d3XPe02QKc9#x9uSPH!J=Q4@dJ zYhBy4<0}JLE$sa<`ct}TM*4Xwqy~bt$L`9IM*?d#Hq182VgxND1L?4_Sjl-oXm_iSPscMwjC1{dJNRC4^>u7%o7BW9gNXY zer~UX(vyE5r|jQ0jSdaX@YLW)lsqWpcoR&gVv>9H0txfH@!#o*^EC7ml}4*=1}5N? zY9%`ia5qQIJ*bEwdvg%s!T_+s+J^7oeoD?O;@iXMho>_SiQ!&pA?u5E6>-5n(sgSv zTnA@)LO$zE0C199*M?OIq9Z;@MCPaUKpDo>AsC=VwKD8a7rK`EO<>C2>YwlvVq9Jm z%xz`IrOJe+6V*ezl35FlAsgN$J1i__ol|a6!W{erXeX!EWM2=qc-P~}*3)Hf1AFE9 z=(-KEScSXqABQ+DSK%ew!0}T%CR3VdFBv9}iP-Z>0D20Sa4{$)w=anIwmhk3LL0Tn zdXO?(MXbx8ji8}-sFVz;?b&nVKkQx4s!!u&$Qk;&?Biz0;Hkl4EJi9jK;~&+>Mp&m zndPmVGb!`6m)R+}Vjm||rI>>G+doeKCw$N>0Q#twsV7Mrx^BtLosZRM4HH!gklXxV zfs>DWp(*x^A8p(J&nT|6R7jJ%@d)*(QU#3Nk2AaJu z`^@U_Lkf&I=_tmcx=<;cWb+uc6R{@M^(;4R{AYF(k28GKzv&DaD+4X*B5_!PM5OC9 zq4E-y*Lt3kjfzN0;KR++@9mrkOmTCNecPNqa3oKaFH#fYJrOBTfm zx`WA=s{V{5b-!YS%)&#I5wK2OC#Pmh`_54*Bb|G)+4}MV>qPlCspgXI7jNB)j6n$Z zFE^t#3U)C+>0mCQH*Tb)V#CM6QmMtqB714$&)B*Z{UnMJ#Z?EQ%e6Xz!<0GX@Qg<6U=5TSy2M3Mr)r+D~4vs z`uf~4C3H_XRmTM5Vuv>-s>SBcmIePxjFHt0AO*mh%;R;9{N_`RPCE3neHk1)Kte5> z?!Fx7abgq{5b+;;A^F;Z4C_F=viOVkIc~S~ijdSyjdF{r;#-<%B%4KqMEW7eccK});y%#EBZ9E0>*V56!AEDVU(_YDS`}n61 zv=|e)!CF3HeAs7NlsN$9!N!80E4Kn1(*Vv-z?X3cjKN)^2=2nxy!ba_Ke#ju#Qlgv zq$#=g=^~H<3pwopxQbmd(-^iQN&HA>d{(+&h;I5+z&P`jow*KbjZIaXT}hDpOYVGX zQ1*>oCUCi(4TwEB1;u#tu5=rd9sV{(a1)|!IC1%M8QiFM9mv`@MDT`4?457iBQfkmO4f?- z)z(4;XdVjy#1=?x|9P5_^#dOdyrtV7aJ$MK6KHu$lcfG(bpO&T zj*{y~i4=h01QvJc@D9zpX-2m2Cz z7KXGvbue^1wRwL7=&;&3p77TC8Ya=#ttAG2qsC7ixg%dYtqEswZn@V2ltA5J1MEgH z_YOX^s6Dl+Sl_XP9-~P)mrFnN)-P{ncJwUPthn}IoxslD+y{p$aXyO=ea_FP zZFC6Usi(Wp+t_m`NNw@sHuPc%6A~)fXeRTbqw!(}hn=R%d>FJl)hRUyKuYZWH(fX` zF4^dHH#MIqAi?}~wA57I>H-Tiv}kRKqXjv*^j*JIF!e)hZ^g8g8Q0EzgIyx@e^_-v$yiuwy4lxLOR>a)n`xp&BY-<)(Tt-eN9Ay zO;iUnJNBD~XH-0Kq*_GdmTvF(wgxVs=3!5gyVdGvElX{m78lJCx=|FZzRD>czvm!X z5Z1nLn|GZkJ4rJisg-g4_xb3JPV-rjO6*ge_%@PkxgP z_L_J;sbTI?!80Jg?f1*=+2Th~*)WHtV4G7z{4LRFekwK^<9Ye8c){C5<`0jDD|-eh zaAj_?HTMs-KlS}ptOri?wX5+RSn44a*;m<)xkYjmGG|IyN?JwbpHfLJ1H6O>b^ZG# zb%_M?8>xIzP3tsC%mUzs=6aRyoXXn-Y^@6>BV|cr@2dP{j%;c(A5}VD*wh-jOoB01 zuFT2-o?miVvCu_V*WYTkVny3;pOB|=z-|64tbuI35! zY?PsW#l2+{ULpg>ow))(-mXN39T#)!X|8m{2i_mXd;cd)QieG0q^@8Zczby3YT1$? zqINFx-L?h`=1(QS&+rshy@A8%6n`%#WZXH6#)OH)o44d!Nnk+{Hs;|697Xp~Kn}zL z1tiJa-$u~scR5hi2?#r;KrkhDQi$>uH<#@NB@mK2`GWmU`UOlg1cw%>CV*cgi{fOj zu#PQD?O60``4KlRd{A6#m;?JXVBm(*zG~}i~I^!t|6?7YRKwP4(QE*)``JsJw z5}lxkP~`vSsmEwLB@y00j_;in6wV)aon(4VJR}8Rk%R2CBLwHWSDM8;V(AWtA2RX& zSQEH_4rcOd=latAu+1nmAGvCVq}4afm62Jnk!C?Mqq9=zI^peZp6gaVjv+J>dvMJj zRFyCkDCoU#!_D~djU#<@fH6s_>f6*VX$xp7TS>AzcouM|rb;r*cS>1d43fwXSZ;gB zq!{>r49g6HWH)bb!ZnQxfl?bLYn=%(rJFnim9dhn$AmTfSBBt(XEAHD)RLke|8BOV z&0N5xP9%1)hs?q&abI!dN6BjiP{9$@m@jWcvjsYrR}?iRyrJyEUNM6ed66w|Ng9E@?QXtvA zS#sgk+UKRi@7rnxphq{RDg*4|Shn9{VNL6!SYsb*lb7BTVeP%J)gbsUOghQUKcEP;b87^TKagQO%dHp>UwuYIuu&`&Mfq_6JkZIQat{*q=U5WzA(NfhE%R9yvS{Efk;srJ&sl~8~U;z%4voY?E zITa!#C;I0G5sSe?23sz6oSeTLU|(>`e4>&6=Z8B}i&NVBh>O?Lh_10@z71gY3he`o z=ae|zaG_6+5?{&N&0v@BX@v++dK4SfE#MRz@=}9a(pgP{GJ9L#TH6aeyvHziuF99H zfz7S~$*%F9THN@kMSYibD3>i@)SvcLYPo^nRt}@@(`5`0LQ=AiMVnNBoy;MK9AazO zg6B6mF4?2`^fF^hZ3>`eG>Gf8AB}G;&3i)DPR`L2B{s7Qp??u8Hm`$57`Bb_o3gE+ z%4lN2;_kB1^6+_EU_0PXX>@qmiP*^3u`U00BLqGYOHEJ4hohb}D$&MVx#Y1<6W{+;qR3 z$0ALTuwY$0Pc896fc*FFl&Ji}wE@5E!?0C$>%o{qa0LBRUfcPsBp@GELPD|fFsh9S2ocP^}$pr!S11&zQxltRM)tR^fHqACuA{A z{288t6{@zxfSt{n+Sx!_^yNnYAG%a64`pe%TsJ<}Q>}Xfnall;OGdXdqKhP0t#=;Fk2@Xp5#>^;ATfcTp)0^jk0J|wgd?q zND6F9Jz8SW^Drwp%=)Tfff1va({yZ!Hj#4JV6^{rcZ(QMZn<$qYI2QAayLRZs-Ya~KPbMF@fw^tPI$a%@{R2K(nKOoLd0mC1`jOwpNENka%X5 zVXHEpMJ&UlF&L+vlmMvc4G#)WT{%JEO5`iIkZ@s@o3kYy)GWrVJC}#X!HCy!ZY*SW z^GGYFy&f$O*AVp!m5mzv@EAQd`9~00PGm6&f~2 zH>gk-7Y*J`#gNj3HSklgLjDegEQo$4Dw&R-CqoZfkV-Wm`0ap*YncdIntz>EHCtj0 zL|It$)-*M_BoH2?&oM;Zt{cFpYWAr;qy)MYq0vbus__cJ- zM6l+QHO7Cb$%|R@x|S&`+df(&;|(In6?v^B_6pLUkwM_P1jv+U09t1C+Xak{ZqQj; zh>OB1HCI!Uz!bE>$?{8?-V%?@B%=1%AWG^qg^P#N|caMI733v^HzjYI_5OL}P zEuS+4wnpo3`A-p=j2ckeY*V+;6$SBQs6yw<)^hi)HRz0))&j)}owN8xWvQX@2V93k zu@NbEqjpXx45C1FOR35kYVxgyOHK4h+CFi4GmMxkecQSy6ATDF=n3?whpEb~?x-I@ zHYVzmxZpPui%+4H$g0CiG3NmvAPk;1X)7&$qy`8fX7d1L3F7be{(ka=RofSPVky$M zbr$Mp?xg~~%!|w2%dcM5Cu{KLAN84H+(ZIeXWMe|WRQj`QNbvcZibbAIWaaGzn`g` zejc#6w$0KRp3}0~cz{_`MD?x6xO3ccZy3qg-4^%Uui2h3-x8jYC?LB z6dILfsM(theW3-gilqxQO4EDU1~KW^T>C_;65s}3@>0fvo`nFrHzS|RbHXMzg<}pl z`=Xo~kLf-`Vf6S5l^p38@J{8&yoSiSJj)@_oF7&*{yCeES=)+vS;t**qIG_jpn@J^ zk}`R6TP6Yf1jn`_Z50d~5|($Gh9ZmdMAnE~RV@uWBk1~5->o>OK9XHOv(>}rCIay#xQE^k*0|x_8N>N)K zB&b^vY9K`2wG?y-4<)TPPfi{-?}it*T-K0hALsn+D3K@LngAjylCue6x?&z6G_!8Z z71vUXFh6#qWZST$xw?EIBuWs0O{3HM=-8*UNz3q$b}|zh~ZPSx%twQv3`h#BVzMNt=8D*r2nFPehpus~n@cL5jVZmT8 zspgqQkWbNaHR&(KbPww7fI$rtEBBpIJzpje4mRZc)+m!VW_(FcMX>{c7P9=;zfxy_R~^mQ?qaQzC0C>UM*>qB^Bk6ttvl@d z9x;EVaIOoe^;1uc}`x_~`%HYQ9L=>Rr*(tnk;C@$lmxF(#p47cXiTDvve zNYF2AVq-x4$)yRc`hXTL+VrVzJxNQ(6D)!{aWGdqm$V&KGr!JipiaNA4D02MnB#Cf z$AK{nwgM#^d=iXppeW@Ey4qWX8@|lgl(ecfHBJoQ$potX?$7~B47Ky!{T6vCOL6QQ zndOyN*+Ba5eSK?Pu$DA9pZIq7n?Pt5N7YC6$7i`ShiCYhDnhdy8BWtM^>|Ni!gI^b zVy_=?=yd}v$-Gv@f7`iAgGrQXTeP@B1805SOL-uVy7uNYiSKUmqkSY`JN)ptgKud} z4{IGbGK?91aePpKeM0fE1C#3BC`!>#!kKY{FD^ux6D<3Ipx^9Xk=_2a`yiGPjR9jf z%X#YPbAyd0j0Yg)rk$riYczhC!wIO1#1`#tnN2SdhXFZ27Z<4h>~-c?L0RgTWXIPHZ&7|zi+kuAYeBh%p= zJ7z{jPH3Gkb4)5cQ=B&XG&B#&nzmIES0K3W5DzNFo}GEWmn#PVp0laSMxeBT_iNvA z9mL8n(|1@152DM6{i`>5+jw*-oH3{M?R&sBZ!}PS=CqY8|LA*U3=V=PJ0nnV-4F1) zRtwmsn(Y7o4#3)spQP1cbw!{j9LD-cn|C`Xjh|=lqIZ-Ty#f$NFPbg<{6sSbyxNVt zm2-1n**Jtpim~Y>=j*^~tz2n~Fr zN(Knaiwomup(d-=(6dolxtjwf`Z``=YQqsZ_#K#rK{?Nx77e+CLv2WPx149Z#mm)i zRlSX!R5^BoI@4)IDd=0JXlp`tFuzDxbH4;AF}8#^Ku}lCN3W@Q7X!A6{-*|%|aN+Y?*}Ar|HLiiB z3bj0#Oqs`u88fRK(m3n^U-E|nz{an#i#K>nEKlLB(7Qp-H|a$+5A!k^)YMo-5BOXA zX?sNVwMN{j-b(79uAso$G%avRQBF9Ns(~e~zKXo}stDrAsco3>fv`3 z`MdlJ7v(VLW~99!Nrr|DD{TSPhvX_&^UbcjMP& z3NJx23nUB@?|Q^0_GfL|Df!dO_ef+rr9FJa4y%X(U=bFfZjp&?rVCy1#BHos)#?$bVtd=m5J*G~m}OPg>G@xb!RFi)EkUOI3PD#6<_o8B}=Rh&ke+J$NBo!-#cn)bwk2YGRp0kqQK zeDqcASbX-mO7eM~6?CNTRb>l$?2CJFi-@Uj0RbB@Nm@PiC{(e>l2JB(?u^YecS>>J+mmQ7Og=sIOO z^wb!@w@x&}Bt(aJe!$TXg$KCndfU{dA3X%C=wVcwUG67CDmt)69pe3W(#4-yitCe#@XMB?>VV z5%P=(R#N&e%sU~qwD`TS8|Aty$^UWc?8h={yZ-zVZ?O(|m#EAU+x&6SDp@PIU6i!~v$f9#a4ecBf@2%H|Y&99=j+x{daHj#e z1=Ba;BZC2vMfXbxFkGlbElgo65O`s-Aq1T8STqGGWz96+-N|)bQ`aT%z%U|eFMLwmF^1ISqEt$0@uuQfuTqUbQ)qu{~s!aG-vn~$LDuf>9Ou+|w zzz(|Cp5rSAZ0G2uR_@5c)S-XF7bW?@6#iG?`_NH+A=;L@{B=wqJhxXq4Z#s{G|pdy z<(>5iA=z-@mGKE}pCzj=b^Sbu=a4)=_dHCSQwLAyLZ&(Dvs4roqP7I5JUtgj?o3>oSVA24XKkE5&=QO+#o1lxYCU^m zX6XQm*3nkD9KbI~yuEjz9JD2(p3A#YBnz;#)mm9KBRg^sO`q6yrjn(vRAph;o0E+( z2zfKw{0toc1u**1s;Tl|^2o7mqUcQv_3>c&*r$m`_|syJIEh9@bPTjxcGmIv>>@wU z4Cv#!CiNN@HF0O<2M^1iZGnoaJ#ii?rT=>?LJ;DY!c>_`Ik}g4FQ~q=tC@G_Rh&o2 zt8fKKz?x!WOBivLz|wwyq~84`Dh5bPS7Dji49Gi=xml*=P~OKt#%MsBXaZ==M;;Vc zo0Y{W;$L142MI&^Xt!~-2v9B*v>~O}0yubF9ioBPAHW(UageBT)voxOFe=Wdv(sxb z`3d(BKo;!!PXQ>*4^0^2zAA+uAT<#x*ieYB@EyHyX7j@NsPoypH|3x&jpV z8oj28TS5;S%rDCYEs#Ah$8VZ0P8~LpXPv6)O>b=Oh4T zEI2$E1ekHr6SU=}=Zv=QB~&={pwImHWP&i27MHz3wdeBd&(%(~E5i3*6;sU-nSaYK z1~5j{Sk=q|U4o8>Xh4$|IVn9i;m}U52QLLHw5h8^CJ9M5jrtu^0j@~b`R7Tpz7Z32 zGR#oj9eFaep>}bh82QWMZ#j$dFG$oV$r6!jm2+-U(vZR0H7m1rRb7r9cGxL_`-Od> z>(s$lNB1NzFafn^`vO}w$deqXPcERcf%*oHQgsjBcsqldibz};cv9IyVq4ZUkdcY8 z0>e!=Gfc2b`Q?t^AaZB|iLQjLAWBoX4qrK+6krTK7Z|LOHs-)B;k@|_S^Bna(;Yw# zzfxq4mpjBLb<40Gx?(;>iomFfmT)0yEhJ^>Dr_+a7LlMSHsHNA=Q`$G$dy?^Q~>N7 z_3&=?JZ&PCzZ_BsVN3I)#pP9iY1s~D*CVW;=`gv?6(mWJHvG(heUrm}j3#&IzOu*xA5Xd5-&PKxjuP0uFnh!#{MYM8SCkNu?&K6mP-N1}V3@l=n>%Ngih< zXKG?Cj1okVe7Z`?3YtfkU)1bKIY(%j#Ec9MhNY}A?qTwjy+29Zk2bsxAb zvJY#<-s&b?y{Y$R<{wW$Rq~;esgOd9){8_*kuPd1gUr{-P!2hmOoB#j- literal 0 HcmV?d00001 diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index af953100..17fd0da8 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -126,7 +126,24 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun expect(imageView.currentFrame).notTo.beNil(); // current frame } -- (void)test10AnimatedImageViewRendering { +- (void)test10AnimatedImageInitWithCoder { + SDAnimatedImage *image1 = [SDAnimatedImage imageWithContentsOfFile:[self testGIFPath]]; + expect(image1).notTo.beNil(); + NSData *encodedData = [NSKeyedArchiver archivedDataWithRootObject:image1]; + expect(encodedData).notTo.beNil(); + SDAnimatedImage *image2 = [NSKeyedUnarchiver unarchiveObjectWithData:encodedData]; + expect(image2).notTo.beNil(); + + // Check each property + expect(image1.scale).equal(image2.scale); + expect(image1.size).equal(image2.size); + expect(image1.animatedImageFormat).equal(image2.animatedImageFormat); + expect(image1.animatedImageData).equal(image2.animatedImageData); + expect(image1.animatedImageLoopCount).equal(image2.animatedImageLoopCount); + expect(image1.animatedImageFrameCount).equal(image2.animatedImageFrameCount); +} + +- (void)test20AnimatedImageViewRendering { XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView rendering"]; SDAnimatedImageView *imageView = [[SDAnimatedImageView alloc] init]; #if SD_UIKIT @@ -168,7 +185,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun [self waitForExpectationsWithCommonTimeout]; } -- (void)test11AnimatedImageViewSetProgressiveAnimatedImage { +- (void)test21AnimatedImageViewSetProgressiveAnimatedImage { NSData *gifData = [self testGIFData]; SDImageGIFCoder *progressiveCoder = [[SDImageGIFCoder alloc] initIncrementalWithOptions:nil]; // simulate progressive decode, pass partial data @@ -195,7 +212,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun expect(isProgressive).equal(NO); } -- (void)test12AnimatedImageViewCategory { +- (void)test22AnimatedImageViewCategory { XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"]; SDAnimatedImageView *imageView = [SDAnimatedImageView new]; NSURL *testURL = [NSURL URLWithString:kTestWebPURL]; @@ -208,7 +225,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun [self waitForExpectationsWithCommonTimeout]; } -- (void)test13AnimatedImageViewCategoryProgressive { +- (void)test23AnimatedImageViewCategoryProgressive { XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"]; SDAnimatedImageView *imageView = [SDAnimatedImageView new]; NSURL *testURL = [NSURL URLWithString:kTestGIFURL]; diff --git a/Tests/Tests/SDImageCoderTests.m b/Tests/Tests/SDImageCoderTests.m index 84995795..6628571e 100644 --- a/Tests/Tests/SDImageCoderTests.m +++ b/Tests/Tests/SDImageCoderTests.m @@ -83,6 +83,7 @@ NSURL *staticWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageStatic" withExtension:@"webp"]; [self verifyCoder:[SDImageWebPCoder sharedCoder] withLocalImageURL:staticWebPURL + supportsEncoding:YES isAnimatedImage:NO]; } @@ -90,6 +91,7 @@ NSURL *animatedWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageAnimated" withExtension:@"webp"]; [self verifyCoder:[SDImageWebPCoder sharedCoder] withLocalImageURL:animatedWebPURL + supportsEncoding:YES isAnimatedImage:YES]; } @@ -97,18 +99,41 @@ NSURL *animatedWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageAnimated" withExtension:@"apng"]; [self verifyCoder:[SDImageAPNGCoder sharedCoder] withLocalImageURL:animatedWebPURL + supportsEncoding:YES isAnimatedImage:YES]; } -- (void)test20ThatOurGIFCoderWorks { +- (void)test12ThatGIFCoderWorks { NSURL *gifURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImage" withExtension:@"gif"]; [self verifyCoder:[SDImageGIFCoder sharedCoder] withLocalImageURL:gifURL + supportsEncoding:YES isAnimatedImage:YES]; } +- (void)test13ThatHEICWorks { + if (@available(iOS 11, macOS 10.13, *)) { + NSURL *heicURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImage" withExtension:@"heic"]; + [self verifyCoder:[SDImageIOCoder sharedCoder] + withLocalImageURL:heicURL + supportsEncoding:YES + isAnimatedImage:NO]; + } +} + +- (void)test14ThatHEIFWorks { + if (@available(iOS 11, macOS 10.13, *)) { + NSURL *heifURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImage" withExtension:@"heif"]; + [self verifyCoder:[SDImageIOCoder sharedCoder] + withLocalImageURL:heifURL + supportsEncoding:NO + isAnimatedImage:NO]; + } +} + - (void)verifyCoder:(id)coder withLocalImageURL:(NSURL *)imageUrl + supportsEncoding:(BOOL)supportsEncoding isAnimatedImage:(BOOL)isAnimated { NSData *inputImageData = [NSData dataWithContentsOfURL:imageUrl]; expect(inputImageData).toNot.beNil(); @@ -137,18 +162,20 @@ #endif } - // 3 - check if we can encode to the original format - expect([coder canEncodeToFormat:inputImageFormat]).to.beTruthy(); - - // 4 - encode from UIImage to NSData using the inputImageFormat and check it - NSData *outputImageData = [coder encodedDataWithImage:inputImage format:inputImageFormat options:nil]; - expect(outputImageData).toNot.beNil(); - UIImage *outputImage = [coder decodedImageWithData:outputImageData options:nil]; - expect(outputImage.size).to.equal(inputImage.size); - expect(outputImage.scale).to.equal(inputImage.scale); + if (supportsEncoding) { + // 3 - check if we can encode to the original format + expect([coder canEncodeToFormat:inputImageFormat]).to.beTruthy(); + + // 4 - encode from UIImage to NSData using the inputImageFormat and check it + NSData *outputImageData = [coder encodedDataWithImage:inputImage format:inputImageFormat options:nil]; + expect(outputImageData).toNot.beNil(); + UIImage *outputImage = [coder decodedImageWithData:outputImageData options:nil]; + expect(outputImage.size).to.equal(inputImage.size); + expect(outputImage.scale).to.equal(inputImage.scale); #if SD_UIKIT - expect(outputImage.images.count).to.equal(inputImage.images.count); + expect(outputImage.images.count).to.equal(inputImage.images.count); #endif + } } @end diff --git a/Tests/Tests/SDTestCase.m b/Tests/Tests/SDTestCase.m index 0851c8fb..a635caae 100644 --- a/Tests/Tests/SDTestCase.m +++ b/Tests/Tests/SDTestCase.m @@ -16,7 +16,7 @@ NSString *const kTestProgressiveJPEGURL = @"https://raw.githubusercontent.com/ib NSString *const kTestPNGURL = @"http://via.placeholder.com/50x50.png"; NSString *const kTestGIFURL = @"https://media.giphy.com/media/UEsrLdv7ugRTq/giphy.gif"; NSString *const kTestWebPURL = @"http://littlesvr.ca/apng/images/SteamEngine.webp"; -NSString *const kTestAPNGPURL = @"https:raw.githubusercontent.com/onevcat/APNGKit/master/TestImages/APNG-cube.apng"; +NSString *const kTestAPNGPURL = @"https://upload.wikimedia.org/wikipedia/commons/1/14/Animated_PNG_example_bouncing_beach_ball.png"; @implementation SDTestCase From 5ea4b803d05330cbd08aace753722968aae30475 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 10 Aug 2018 15:50:45 +0800 Subject: [PATCH 245/361] Update travis-ci Xcode version to 9.4, fix HEIF/HEIC coder test --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2c9ed21d..bdc805da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: objective-c -osx_image: xcode9 +osx_image: xcode9.4 env: global: @@ -40,9 +40,9 @@ script: - echo Build the Demo apps - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX Demo' -sdk macosx -configuration Debug | xcpretty -c - - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 8' | xcpretty -c - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage TV Demo' -sdk appletvsimulator -configuration Debug | xcpretty -c - - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone 8' | xcpretty -c - echo Clean DerivedData - mkdir DerivedData @@ -50,7 +50,7 @@ script: - echo Run the tests - pod install --project-directory=Tests - - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6s' -configuration Debug | xcpretty -c + - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 8' -configuration Debug | xcpretty -c - mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/iOS - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests Mac' -sdk macosx -destination 'platform=OS X,arch=x86_64' -configuration Debug | xcpretty -c - mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/macOS From 41b0a0421e43289491f0639dc3c11c852976e48c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 10 Aug 2018 21:28:27 +0800 Subject: [PATCH 246/361] Fix the mistake cause a bug that progress indicator on macOS stop at 1% but not 100% when download finished... --- SDWebImage/SDWebImageIndicator.m | 2 +- SDWebImage/UIView+WebCache.m | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SDWebImage/SDWebImageIndicator.m b/SDWebImage/SDWebImageIndicator.m index 53830a37..bec23fbc 100644 --- a/SDWebImage/SDWebImageIndicator.m +++ b/SDWebImage/SDWebImageIndicator.m @@ -192,7 +192,7 @@ } #else self.indicatorView.indeterminate = NO; - self.indicatorView.doubleValue = 1; + self.indicatorView.doubleValue = 100; [self.indicatorView stopAnimation:nil]; #endif } diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 8a73d740..d3b7ef61 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -83,9 +83,6 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; NSProgress *imageProgress = sself.sd_imageProgress; imageProgress.totalUnitCount = expectedSize; imageProgress.completedUnitCount = receivedSize; - if (progressBlock) { - progressBlock(receivedSize, expectedSize, targetURL); - } #if SD_UIKIT || SD_MAC if ([imageIndicator respondsToSelector:@selector(updateIndicatorProgress:)]) { double progress = imageProgress.fractionCompleted; @@ -94,6 +91,9 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; }); } #endif + if (progressBlock) { + progressBlock(receivedSize, expectedSize, targetURL); + } }; id operation = [manager loadImageWithURL:url options:options context:context progress:combinedProgressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { __strong __typeof (wself) sself = wself; From 7ee0d06cf7d712bdab723888ca6b9d69f6f4effa Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 10 Aug 2018 22:19:24 +0800 Subject: [PATCH 247/361] Add the test cases for View Transition and View Indicator, both iOS && macOS --- Tests/Tests/SDAnimatedImageTest.m | 5 - Tests/Tests/SDTestCase.h | 5 + Tests/Tests/SDWebCacheCategoriesTests.m | 137 ++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 5 deletions(-) diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index 43e19d58..2e5dd7c6 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -10,11 +10,6 @@ #import "SDTestCase.h" #import -#if SD_MAC -#define UIWindow NSWindow -#define UIScreen NSScreen -#endif - static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop count // Internal header diff --git a/Tests/Tests/SDTestCase.h b/Tests/Tests/SDTestCase.h index 566381c1..ae5bb06b 100644 --- a/Tests/Tests/SDTestCase.h +++ b/Tests/Tests/SDTestCase.h @@ -14,6 +14,11 @@ #import #import +#if SD_MAC +#define UIWindow NSWindow +#define UIScreen NSScreen +#endif + FOUNDATION_EXPORT const int64_t kAsyncTestTimeout; FOUNDATION_EXPORT const int64_t kMinDelayNanosecond; FOUNDATION_EXPORT NSString * _Nonnull const kTestJpegURL; diff --git a/Tests/Tests/SDWebCacheCategoriesTests.m b/Tests/Tests/SDWebCacheCategoriesTests.m index eedca13b..ab75b35e 100644 --- a/Tests/Tests/SDWebCacheCategoriesTests.m +++ b/Tests/Tests/SDWebCacheCategoriesTests.m @@ -12,6 +12,8 @@ @interface SDWebCacheCategoriesTests : SDTestCase +@property (nonatomic, strong) UIWindow *window; + @end @implementation SDWebCacheCategoriesTests @@ -119,6 +121,40 @@ } #endif +#if SD_MAC +- (void)testNSButtonSetImageWithURL { + XCTestExpectation *expectation = [self expectationWithDescription:@"NSButton setImageWithURL"]; + + NSButton *button = [[NSButton alloc] init]; + NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; + [button sd_setImageWithURL:originalImageURL + completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { + expect(image).toNot.beNil(); + expect(error).to.beNil(); + expect(originalImageURL).to.equal(imageURL); + expect(button.image).to.equal(image); + [expectation fulfill]; + }]; + [self waitForExpectationsWithCommonTimeout]; +} + +- (void)testNSButtonSetAlternateImageWithURL { + XCTestExpectation *expectation = [self expectationWithDescription:@"NSButton setAlternateImageWithURL"]; + + NSButton *button = [[NSButton alloc] init]; + NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; + [button sd_setAlternateImageWithURL:originalImageURL + completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { + expect(image).toNot.beNil(); + expect(error).to.beNil(); + expect(originalImageURL).to.equal(imageURL); + expect(button.alternateImage).to.equal(image); + [expectation fulfill]; + }]; + [self waitForExpectationsWithCommonTimeout]; +} +#endif + - (void)testUIViewImageProgressKVOWork { XCTestExpectation *expectation = [self expectationWithDescription:@"UIView imageProgressKVO failed"]; UIView *view = [[UIView alloc] init]; @@ -143,4 +179,105 @@ [self waitForExpectationsWithCommonTimeout]; } +- (void)testUIViewTransitionWork { + XCTestExpectation *expectation = [self expectationWithDescription:@"UIView transition does not work"]; + + // Attach a window, or CALayer will not submit drawing + UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)]; + imageView.sd_imageTransition = SDWebImageTransition.fadeTransition; + imageView.sd_imageTransition.duration = 1; + +#if SD_UIKIT + [self.window addSubview:imageView]; +#else + imageView.wantsLayer = YES; + [self.window.contentView addSubview:imageView]; +#endif + + UIImage *placeholder = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]]; + + NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; + __weak typeof(imageView) wimageView = imageView; + [imageView sd_setImageWithURL:originalImageURL + placeholderImage:placeholder + options:SDWebImageForceTransition + completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { + __strong typeof(wimageView) simageView = imageView; + // Delay to let CALayer commit the transition in next runloop + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, kMinDelayNanosecond), dispatch_get_main_queue(), ^{ + // Check current view contains layer animation + NSArray *animationKeys = simageView.layer.animationKeys; + expect(animationKeys.count).beGreaterThan(0); + [expectation fulfill]; + }); + }]; + + [self waitForExpectationsWithCommonTimeout]; +} + +- (void)testUIViewIndicatorWork { + XCTestExpectation *expectation = [self expectationWithDescription:@"UIView indicator does not work"]; + + UIImageView *imageView = [[UIImageView alloc] init]; + imageView.sd_imageIndicator = SDWebImageActivityIndicator.grayLargeIndicator; + // Test setter trigger removeFromSuperView + imageView.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator; + + NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; + __weak typeof(imageView) wimageView = imageView; + [imageView sd_setImageWithURL:originalImageURL + placeholderImage:nil options:SDWebImageFromLoaderOnly progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { + dispatch_async(dispatch_get_main_queue(), ^{ + __strong typeof(wimageView) simageView = imageView; + UIView *indicatorView = simageView.subviews.firstObject; + expect(indicatorView).equal(simageView.sd_imageIndicator.indicatorView); + + if (receivedSize <= 0 || expectedSize <= 0) { + return; + } + + // Current progess indicator update is called after progressBlock + double progress = 0; + double imageProgress = (double)receivedSize / (double)expectedSize; +#if SD_UIKIT + progress = ((UIProgressView *)simageView.sd_imageIndicator.indicatorView).progress; +#else + progress = ((NSProgressIndicator *)simageView.sd_imageIndicator.indicatorView).doubleValue / 100; +#endif + expect(progress).equal(imageProgress); + }); + } completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { + __strong typeof(wimageView) simageView = imageView; + double progress = 0; +#if SD_UIKIT + progress = ((UIProgressView *)simageView.sd_imageIndicator.indicatorView).progress; +#else + progress = ((NSProgressIndicator *)simageView.sd_imageIndicator.indicatorView).doubleValue / 100; +#endif + // Finish progress is 1 + expect(progress).equal(1); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithCommonTimeout]; +} + +#pragma mark - Helper +- (UIWindow *)window { + if (!_window) { + UIScreen *mainScreen = [UIScreen mainScreen]; +#if SD_UIKIT + _window = [[UIWindow alloc] initWithFrame:mainScreen.bounds]; +#else + _window = [[NSWindow alloc] initWithContentRect:mainScreen.frame styleMask:0 backing:NSBackingStoreBuffered defer:NO screen:mainScreen]; +#endif + } + return _window; +} + +- (NSString *)testJPEGPath { + NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; + return [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; +} + @end From 1d8454d3563a26868ff5369a10b8a68c9a026d2e Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 10 Aug 2018 07:53:43 +0800 Subject: [PATCH 248/361] Fix that the minimumProgressInterval should always callback the final finished progress but not ignore it --- SDWebImage/SDWebImageDownloaderConfig.h | 4 ++-- SDWebImage/SDWebImageDownloaderOperation.h | 8 ++++---- SDWebImage/SDWebImageDownloaderOperation.m | 7 ++----- Tests/Tests/SDWebImageDownloaderTests.m | 4 ++-- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/SDWebImage/SDWebImageDownloaderConfig.h b/SDWebImage/SDWebImageDownloaderConfig.h index 00f15496..669d13a5 100644 --- a/SDWebImage/SDWebImageDownloaderConfig.h +++ b/SDWebImage/SDWebImageDownloaderConfig.h @@ -42,13 +42,13 @@ typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { @property (nonatomic, assign) NSTimeInterval downloadTimeout; /** - * The minimum interval about progress percent during network downloading. Which means the next progress callback and current progress callback's progress percent difference should be larger or equal to this value. + * The minimum interval about progress percent during network downloading. Which means the next progress callback and current progress callback's progress percent difference should be larger or equal to this value. However, the final finish download progress callback does not get effected. * The value should be 0.0-1.0. * @note If you're using progressive decoding feature, this will also effect the image refresh rate. * @note This value may enhance the performance if you don't want progress callback too frequently. * Defaults to 0, which means each time we receive the new data from URLSession, we callback the progressBlock immediately. */ -@property (nonatomic, assign) NSTimeInterval minimumProgressInterval; +@property (nonatomic, assign) double minimumProgressInterval; /** * The custom session configuration in use by NSURLSession. If you don't provide one, we will use `defaultSessionConfiguration` instead. diff --git a/SDWebImage/SDWebImageDownloaderOperation.h b/SDWebImage/SDWebImageDownloaderOperation.h index ff5c6129..f7f9f07e 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.h +++ b/SDWebImage/SDWebImageDownloaderOperation.h @@ -45,8 +45,8 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification - (nullable NSURLSessionTask *)dataTask; - (nullable NSURLCredential *)credential; - (void)setCredential:(nullable NSURLCredential *)credential; -- (NSTimeInterval)minimumProgressInterval; -- (void)setMinimumProgressInterval:(NSTimeInterval)minimumProgressInterval; +- (double)minimumProgressInterval; +- (void)setMinimumProgressInterval:(double)minimumProgressInterval; @end @@ -76,13 +76,13 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification @property (nonatomic, strong, nullable) NSURLCredential *credential; /** - * The minimum interval about progress percent during network downloading. Which means the next progress callback and current progress callback's progress percent difference should be larger or equal to this value. + * The minimum interval about progress percent during network downloading. Which means the next progress callback and current progress callback's progress percent difference should be larger or equal to this value. However, the final finish download progress callback does not get effected. * The value should be 0.0-1.0. * @note If you're using progressive decoding feature, this will also effect the image refresh rate. * @note This value may enhance the performance if you don't want progress callback too frequently. * Defaults to 0, which means each time we receive the new data from URLSession, we callback the progressBlock immediately. */ -@property (assign, nonatomic) NSTimeInterval minimumProgressInterval; +@property (assign, nonatomic) double minimumProgressInterval; /** * The options for the receiver. diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index a6c13fa7..8bdfa27a 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -348,8 +348,9 @@ didReceiveResponse:(NSURLResponse *)response // Get the current progress double currentProgress = (double)self.receivedSize / (double)self.expectedSize; double previousProgress = self.previousProgress; + double progressInterval = currentProgress - previousProgress; // Check if we need callback progress - if (currentProgress - previousProgress < self.minimumProgressInterval) { + if (!finished && (progressInterval < self.minimumProgressInterval)) { return; } self.previousProgress = currentProgress; @@ -360,10 +361,6 @@ didReceiveResponse:(NSURLResponse *)response // progressive decode the image in coder queue dispatch_async(self.coderQueue, ^{ - // If all the data has already been downloaded, earily return to avoid further decoding - if (self.receivedSize >= self.expectedSize) { - return; - } UIImage *image = SDImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, finished, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); if (image) { // We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding. diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index d668e1a2..a6bcd8fb 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -262,7 +262,7 @@ - (void)test17ThatMinimumProgressIntervalWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Minimum progress interval"]; SDWebImageDownloaderConfig *config = SDWebImageDownloaderConfig.defaultDownloaderConfig; - config.minimumProgressInterval = 0.51; // This will make the progress only callback once + config.minimumProgressInterval = 0.51; // This will make the progress only callback twice (once is 51%, another is 100%) SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] initWithConfig:config]; NSURL *imageURL = [NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp"]; __block NSUInteger allProgressCount = 0; // All progress (including operation start / first HTTP response, etc) @@ -275,7 +275,7 @@ } validProgressCount++; } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { - if (allProgressCount > 1 && validProgressCount == 1) { + if (allProgressCount > 2 && validProgressCount == 2) { [expectation fulfill]; } else { XCTFail(@"Progress callback more than once"); From 30d077b0a649fabccd4324ba219250c2ddb96cae Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 10 Aug 2018 22:53:13 +0800 Subject: [PATCH 249/361] Make callbacks of download more readable --- SDWebImage/SDWebImageDownloaderOperation.m | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 2690beab..a6c13fa7 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -105,15 +105,10 @@ typedef NSMutableDictionary SDCallbacksDictionary; - (nullable NSArray *)callbacksForKey:(NSString *)key { LOCK(self.callbacksLock); - NSArray *callbackBlocks = [self.callbackBlocks copy]; + NSMutableArray *callbacks = [[self.callbackBlocks valueForKey:key] mutableCopy]; UNLOCK(self.callbacksLock); - NSMutableArray *callbacks = [NSMutableArray arrayWithCapacity:callbackBlocks.count]; - for (SDCallbacksDictionary *callbacksDic in callbackBlocks) { - id callback = callbacksDic[key]; - if (callback) { - [callbacks addObject:callback]; - } - } + // We need to remove [NSNull null] because there might not always be a progress block for each callback + [callbacks removeObjectIdenticalTo:[NSNull null]]; return [callbacks copy]; // strip mutability here } From 0ff95e225585b3954005b9b339900925d5b73c88 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 10 Aug 2018 23:21:27 +0800 Subject: [PATCH 250/361] Update the view indicator and transition test --- Tests/Tests/SDWebCacheCategoriesTests.m | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Tests/Tests/SDWebCacheCategoriesTests.m b/Tests/Tests/SDWebCacheCategoriesTests.m index ab75b35e..6205b1e4 100644 --- a/Tests/Tests/SDWebCacheCategoriesTests.m +++ b/Tests/Tests/SDWebCacheCategoriesTests.m @@ -184,7 +184,14 @@ // Attach a window, or CALayer will not submit drawing UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)]; + // Cover each convenience method imageView.sd_imageTransition = SDWebImageTransition.fadeTransition; + imageView.sd_imageTransition = SDWebImageTransition.flipFromTopTransition; + imageView.sd_imageTransition = SDWebImageTransition.flipFromLeftTransition; + imageView.sd_imageTransition = SDWebImageTransition.flipFromBottomTransition; + imageView.sd_imageTransition = SDWebImageTransition.flipFromRightTransition; + imageView.sd_imageTransition = SDWebImageTransition.curlUpTransition; + imageView.sd_imageTransition = SDWebImageTransition.curlDownTransition; imageView.sd_imageTransition.duration = 1; #if SD_UIKIT @@ -219,9 +226,17 @@ XCTestExpectation *expectation = [self expectationWithDescription:@"UIView indicator does not work"]; UIImageView *imageView = [[UIImageView alloc] init]; + imageView.sd_imageIndicator = SDWebImageActivityIndicator.grayIndicator; + // Cover each convience method, finally use progress indicator for test imageView.sd_imageIndicator = SDWebImageActivityIndicator.grayLargeIndicator; - // Test setter trigger removeFromSuperView + imageView.sd_imageIndicator = SDWebImageActivityIndicator.whiteIndicator; + imageView.sd_imageIndicator = SDWebImageActivityIndicator.whiteLargeIndicator; +#if SD_IOS + imageView.sd_imageIndicator = SDWebImageProgressIndicator.barIndicator; +#endif imageView.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator; + // Test setter trigger removeFromSuperView + expect(imageView.subviews.count).equal(1); NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; __weak typeof(imageView) wimageView = imageView; @@ -236,7 +251,7 @@ return; } - // Current progess indicator update is called after progressBlock + // Base on current implementation, since we dispatch the progressBlock to main queue, the indicator's progress state should be synchonized double progress = 0; double imageProgress = (double)receivedSize / (double)expectedSize; #if SD_UIKIT From 8b26091741ef11fbd114fc0945b6d43b6c678d1f Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 10 Aug 2018 23:49:35 +0800 Subject: [PATCH 251/361] Disable HEIC encoding check temporally for travis-ci --- Tests/Tests/SDImageCoderTests.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Tests/Tests/SDImageCoderTests.m b/Tests/Tests/SDImageCoderTests.m index 6628571e..c8d606fa 100644 --- a/Tests/Tests/SDImageCoderTests.m +++ b/Tests/Tests/SDImageCoderTests.m @@ -114,9 +114,14 @@ - (void)test13ThatHEICWorks { if (@available(iOS 11, macOS 10.13, *)) { NSURL *heicURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImage" withExtension:@"heic"]; +#if SD_UIKIT + BOOL supportsEncoding = YES; // iPhone Simulator after Xcode 9.3 support HEIC encoding +#else + BOOL supportsEncoding = NO; // Travis-CI Mac env currently does not support HEIC encoding +#endif [self verifyCoder:[SDImageIOCoder sharedCoder] withLocalImageURL:heicURL - supportsEncoding:YES + supportsEncoding:supportsEncoding isAnimatedImage:NO]; } } From a6a8308c15d73a8b9f3164affea8ff075da6bbe7 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 16 Aug 2018 11:32:12 +0800 Subject: [PATCH 252/361] Change the View Category setImageBlock with all args like View Transition or CompletedBlock, to make it useful for advanced usage --- SDWebImage/MapKit/MKAnnotationView+WebCache.m | 2 +- SDWebImage/NSButton+WebCache.m | 2 +- SDWebImage/UIButton+WebCache.m | 4 ++-- SDWebImage/UIImageView+HighlightedWebCache.m | 2 +- SDWebImage/UIView+WebCache.h | 2 +- SDWebImage/UIView+WebCache.m | 22 +++++++++---------- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/SDWebImage/MapKit/MKAnnotationView+WebCache.m b/SDWebImage/MapKit/MKAnnotationView+WebCache.m index 15bb528d..a6721a9e 100644 --- a/SDWebImage/MapKit/MKAnnotationView+WebCache.m +++ b/SDWebImage/MapKit/MKAnnotationView+WebCache.m @@ -59,7 +59,7 @@ placeholderImage:placeholder options:options context:context - setImageBlock:^(UIImage *image, NSData *imageData) { + setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { weakSelf.image = image; } progress:progressBlock diff --git a/SDWebImage/NSButton+WebCache.m b/SDWebImage/NSButton+WebCache.m index e7f74844..74383054 100644 --- a/SDWebImage/NSButton+WebCache.m +++ b/SDWebImage/NSButton+WebCache.m @@ -126,7 +126,7 @@ static NSString * const SDAlternateImageOperationKey = @"NSButtonAlternateImageO placeholderImage:placeholder options:options context:mutableContext - setImageBlock:^(NSImage * _Nullable image, NSData * _Nullable imageData) { + setImageBlock:^(NSImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { weakSelf.alternateImage = image; } progress:progressBlock diff --git a/SDWebImage/UIButton+WebCache.m b/SDWebImage/UIButton+WebCache.m index 8da05c77..54034780 100644 --- a/SDWebImage/UIButton+WebCache.m +++ b/SDWebImage/UIButton+WebCache.m @@ -109,7 +109,7 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat placeholderImage:placeholder options:options context:mutableContext - setImageBlock:^(UIImage *image, NSData *imageData) { + setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { [weakSelf setImage:image forState:state]; } progress:progressBlock @@ -193,7 +193,7 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat placeholderImage:placeholder options:options context:mutableContext - setImageBlock:^(UIImage *image, NSData *imageData) { + setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { [weakSelf setBackgroundImage:image forState:state]; } progress:progressBlock diff --git a/SDWebImage/UIImageView+HighlightedWebCache.m b/SDWebImage/UIImageView+HighlightedWebCache.m index a8803aa3..6560f46f 100644 --- a/SDWebImage/UIImageView+HighlightedWebCache.m +++ b/SDWebImage/UIImageView+HighlightedWebCache.m @@ -58,7 +58,7 @@ static NSString * const SDHighlightedImageOperationKey = @"UIImageViewImageOpera placeholderImage:nil options:options context:mutableContext - setImageBlock:^(UIImage *image, NSData *imageData) { + setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { weakSelf.highlightedImage = image; } progress:progressBlock diff --git a/SDWebImage/UIView+WebCache.h b/SDWebImage/UIView+WebCache.h index 10a383d3..42d83054 100644 --- a/SDWebImage/UIView+WebCache.h +++ b/SDWebImage/UIView+WebCache.h @@ -17,7 +17,7 @@ */ FOUNDATION_EXPORT const int64_t SDWebImageProgressUnitCountUnknown; /* 1LL */ -typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable imageData); +typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL); @interface UIView (WebCache) diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 34367b1b..69ef9b27 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -53,7 +53,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; if (!(options & SDWebImageDelayPlaceholder)) { dispatch_main_async_safe(^{ - [self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock]; + [self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock cacheType:SDImageCacheTypeNone imageURL:url]; }); } @@ -151,7 +151,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; #if SD_UIKIT || SD_MAC [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL]; #else - [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock]; + [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock cacheType:cacheType imageURL:imageURL]; #endif callCompletedBlockClojure(); }); @@ -174,13 +174,13 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; [self sd_cancelImageLoadOperationWithKey:NSStringFromClass([self class])]; } -- (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock { +- (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock cacheType:(SDImageCacheType)cacheType imageURL:(NSURL *)imageURL { #if SD_UIKIT || SD_MAC - [self sd_setImage:image imageData:imageData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:nil cacheType:0 imageURL:nil]; + [self sd_setImage:image imageData:imageData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:nil cacheType:cacheType imageURL:imageURL]; #else // watchOS does not support view transition. Simplify the logic if (setImageBlock) { - setImageBlock(image, imageData); + setImageBlock(image, imageData, cacheType, imageURL); } else if ([self isKindOfClass:[UIImageView class]]) { UIImageView *imageView = (UIImageView *)self; [imageView setImage:image]; @@ -196,14 +196,14 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; finalSetImageBlock = setImageBlock; } else if ([view isKindOfClass:[UIImageView class]]) { UIImageView *imageView = (UIImageView *)view; - finalSetImageBlock = ^(UIImage *setImage, NSData *setImageData) { + finalSetImageBlock = ^(UIImage *setImage, NSData *setImageData, SDImageCacheType setCacheType, NSURL *setImageURL) { imageView.image = setImage; }; } #if SD_UIKIT else if ([view isKindOfClass:[UIButton class]]) { UIButton *button = (UIButton *)view; - finalSetImageBlock = ^(UIImage *setImage, NSData *setImageData){ + finalSetImageBlock = ^(UIImage *setImage, NSData *setImageData, SDImageCacheType setCacheType, NSURL *setImageURL) { [button setImage:setImage forState:UIControlStateNormal]; }; } @@ -211,7 +211,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; #if SD_MAC else if ([view isKindOfClass:[NSButton class]]) { NSButton *button = (NSButton *)view; - finalSetImageBlock = ^(UIImage *setImage, NSData *setImageData){ + finalSetImageBlock = ^(UIImage *setImage, NSData *setImageData, SDImageCacheType setCacheType, NSURL *setImageURL) { button.image = setImage; }; } @@ -227,7 +227,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; } completion:^(BOOL finished) { [UIView transitionWithView:view duration:transition.duration options:transition.animationOptions animations:^{ if (finalSetImageBlock && !transition.avoidAutoSetImage) { - finalSetImageBlock(image, imageData); + finalSetImageBlock(image, imageData, cacheType, imageURL); } if (transition.animations) { transition.animations(view, image); @@ -247,7 +247,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; context.timingFunction = transition.timingFunction; context.allowsImplicitAnimation = (transition.animationOptions & SDWebImageAnimationOptionAllowsImplicitAnimation); if (finalSetImageBlock && !transition.avoidAutoSetImage) { - finalSetImageBlock(image, imageData); + finalSetImageBlock(image, imageData, cacheType, imageURL); } if (transition.animations) { transition.animations(view, image); @@ -261,7 +261,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; #endif } else { if (finalSetImageBlock) { - finalSetImageBlock(image, imageData); + finalSetImageBlock(image, imageData, cacheType, imageURL); } } } From 04becbb02b3b6c97dbf39233e664d2afa2ab8b44 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 16 Aug 2018 11:45:51 +0800 Subject: [PATCH 253/361] Update the test to ensure the UIView sd_internalSetImageWithURL of setImageBlock behavior --- Tests/Tests/SDWebCacheCategoriesTests.m | 40 +++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Tests/Tests/SDWebCacheCategoriesTests.m b/Tests/Tests/SDWebCacheCategoriesTests.m index eedca13b..e55af58a 100644 --- a/Tests/Tests/SDWebCacheCategoriesTests.m +++ b/Tests/Tests/SDWebCacheCategoriesTests.m @@ -119,6 +119,40 @@ } #endif +- (void)testUIViewInternalSetImageWithURL { + XCTestExpectation *expectation = [self expectationWithDescription:@"UIView internalSetImageWithURL"]; + + UIView *view = [[UIView alloc] init]; +#if SD_MAC + view.wantsLayer = YES; +#endif + NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; + UIImage *placeholder = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]]; + [view sd_internalSetImageWithURL:originalImageURL + placeholderImage:placeholder + options:0 + context:nil + setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { + if (!imageData && cacheType == SDImageCacheTypeNone) { + // placeholder + expect(image).to.equal(placeholder); + } else { + // cache or download + expect(image).toNot.beNil(); + } + view.layer.contents = (__bridge id _Nullable)(image.CGImage); + } + progress:nil + completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + expect(image).toNot.beNil(); + expect(error).to.beNil(); + expect(originalImageURL).to.equal(imageURL); + expect((__bridge CGImageRef)view.layer.contents == image.CGImage).to.beTruthy(); + [expectation fulfill]; + }]; + [self waitForExpectationsWithCommonTimeout]; +} + - (void)testUIViewImageProgressKVOWork { XCTestExpectation *expectation = [self expectationWithDescription:@"UIView imageProgressKVO failed"]; UIView *view = [[UIView alloc] init]; @@ -143,4 +177,10 @@ [self waitForExpectationsWithCommonTimeout]; } +- (NSString *)testJPEGPath { + NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; + NSString *testPath = [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; + return testPath; +} + @end From b400b51cca292891061ddd8abb57c9291e4d02a9 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 17 Aug 2018 17:20:17 +0800 Subject: [PATCH 254/361] Fix the bug that `SDWebImageContextCacheKeyFilter` wrongly be used as cache serializer and cause crash --- SDWebImage/SDWebImageManager.m | 2 +- Tests/Tests/SDWebImageManagerTests.m | 40 +++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index bddb4c85..0cde8804 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -283,7 +283,7 @@ static id _defaultImageLoader; id cacheKeyFilter = context[SDWebImageContextCacheKeyFilter]; NSString *key = [self cacheKeyForURL:url cacheKeyFilter:cacheKeyFilter]; id transformer = context[SDWebImageContextImageTransformer]; - id cacheSerializer = context[SDWebImageContextCacheKeyFilter]; + id cacheSerializer = context[SDWebImageContextCacheSerializer]; if (downloadedImage && (!downloadedImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage)) && transformer) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ UIImage *transformedImage = [transformer transformedImageWithImage:downloadedImage forKey:key]; diff --git a/Tests/Tests/SDWebImageManagerTests.m b/Tests/Tests/SDWebImageManagerTests.m index 0252595f..8e670e07 100644 --- a/Tests/Tests/SDWebImageManagerTests.m +++ b/Tests/Tests/SDWebImageManagerTests.m @@ -113,9 +113,8 @@ XCTestExpectation *expectation = [self expectationWithDescription:@"Image transformer work"]; NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; SDWebImageTestTransformer *transformer = [[SDWebImageTestTransformer alloc] init]; - NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; - NSString *testImagePath = [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; - transformer.testImage = [[UIImage alloc] initWithContentsOfFile:testImagePath]; + + transformer.testImage = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]]; SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:[SDImageCache sharedImageCache] loader:[SDWebImageDownloader sharedDownloader]]; manager.transformer = transformer; [[SDImageCache sharedImageCache] removeImageForKey:kTestJPEGURL withCompletion:^{ @@ -128,4 +127,39 @@ [self waitForExpectationsWithCommonTimeout]; } +- (void)test09ThatCacheKeyFilterWork { + XCTestExpectation *expectation = [self expectationWithDescription:@"Cache key filter work"]; + NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; + + NSString *cacheKey = @"kTestJPEGURL"; + SDWebImageCacheKeyFilter *cacheKeyFilter = [SDWebImageCacheKeyFilter cacheKeyFilterWithBlock:^NSString * _Nullable(NSURL * _Nonnull url) { + if ([url isEqual:imageURL]) { + return cacheKey; + } else { + return url.absoluteString; + } + }]; + + SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:[SDImageCache sharedImageCache] loader:[SDWebImageDownloader sharedDownloader]]; + manager.cacheKeyFilter = cacheKeyFilter; + // Check download and retrieve custom cache key + [manager loadImageWithURL:imageURL options:0 context:@{SDWebImageContextStoreCacheType : @(SDImageCacheTypeMemory)} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + expect(cacheType).equal(SDImageCacheTypeNone); + + // Check memory cache exist + [manager.imageCache containsImageForKey:cacheKey cacheType:SDImageCacheTypeMemory completion:^(SDImageCacheType containsCacheType) { + expect(containsCacheType).equal(SDImageCacheTypeMemory); + + [expectation fulfill]; + }]; + }]; + + [self waitForExpectationsWithCommonTimeout]; +} + +- (NSString *)testJPEGPath { + NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; + return [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; +} + @end From 0fb7268d2ed589e1f7209dc98662612615e22af8 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 17 Aug 2018 17:58:27 +0800 Subject: [PATCH 255/361] Add the test case for cache serializer feature --- Tests/Tests/SDWebImageManagerTests.m | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Tests/Tests/SDWebImageManagerTests.m b/Tests/Tests/SDWebImageManagerTests.m index 8e670e07..380a019d 100644 --- a/Tests/Tests/SDWebImageManagerTests.m +++ b/Tests/Tests/SDWebImageManagerTests.m @@ -157,6 +157,34 @@ [self waitForExpectationsWithCommonTimeout]; } +- (void)test10ThatCacheSerializerWork { + XCTestExpectation *expectation = [self expectationWithDescription:@"Cache serializer work"]; + NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; + __block NSData *imageData; + + SDWebImageCacheSerializer *cacheSerializer = [SDWebImageCacheSerializer cacheSerializerWithBlock:^NSData * _Nullable(UIImage * _Nonnull image, NSData * _Nullable data, NSURL * _Nullable imageURL) { + imageData = [image sd_imageDataAsFormat:SDImageFormatPNG]; + return imageData; + }]; + + SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:[SDImageCache sharedImageCache] loader:[SDWebImageDownloader sharedDownloader]]; + manager.cacheSerializer = cacheSerializer; + // Check download and store custom disk data + [[SDImageCache sharedImageCache] removeImageForKey:kTestJPEGURL withCompletion:^{ + [manager loadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + // Dispatch to let store disk finish + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, kMinDelayNanosecond), dispatch_get_main_queue(), ^{ + NSData *diskImageData = [[SDImageCache sharedImageCache] diskImageDataForKey:kTestJPEGURL]; + expect(diskImageData).equal(imageData); // disk data equal to serializer data + + [expectation fulfill]; + }); + }]; + }]; + + [self waitForExpectationsWithCommonTimeout]; +} + - (NSString *)testJPEGPath { NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; return [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; From 8c5db9484b0cb985c8fde945bd1e9ab87238ad5c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 19 Aug 2018 12:09:31 +0800 Subject: [PATCH 256/361] Adopt all the protocol APIs which contains getter value to use property instead, to make the API easy to use or Swift user --- SDWebImage/SDAnimatedImage.h | 2 +- SDWebImage/SDDiskCache.h | 4 ++-- SDWebImage/SDDiskCache.m | 4 ++-- SDWebImage/SDImageCoder.h | 6 +++--- SDWebImage/SDImageTransformer.h | 2 +- SDWebImage/SDWebImageDownloaderOperation.h | 16 +++++++--------- SDWebImage/SDWebImageIndicator.h | 2 +- Tests/Tests/SDWebImageTestCache.m | 4 ++-- 8 files changed, 19 insertions(+), 21 deletions(-) diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h index 4a8a5270..6ae98571 100644 --- a/SDWebImage/SDAnimatedImage.h +++ b/SDWebImage/SDAnimatedImage.h @@ -43,7 +43,7 @@ /** Returns a Boolean value indicating whether all animated image frames are already pre-loaded into memory. */ -- (BOOL)isAllFramesLoaded; +@property (nonatomic, assign, readonly, getter=isAllFramesLoaded) BOOL allFramesLoaded; @end diff --git a/SDWebImage/SDDiskCache.h b/SDWebImage/SDDiskCache.h index 02e42d66..fbe893f5 100644 --- a/SDWebImage/SDDiskCache.h +++ b/SDWebImage/SDDiskCache.h @@ -85,7 +85,7 @@ @return The total data count. */ -- (NSInteger)totalCount; +- (NSUInteger)totalCount; /** Returns the total size (in bytes) of data in this cache. @@ -93,7 +93,7 @@ @return The total data size in bytes. */ -- (NSInteger)totalSize; +- (NSUInteger)totalSize; @end diff --git a/SDWebImage/SDDiskCache.m b/SDWebImage/SDDiskCache.m index ebf40fcf..539cd68b 100644 --- a/SDWebImage/SDDiskCache.m +++ b/SDWebImage/SDDiskCache.m @@ -203,7 +203,7 @@ return [self cachePathForKey:key inPath:self.diskCachePath]; } -- (NSInteger)totalSize { +- (NSUInteger)totalSize { NSUInteger size = 0; NSDirectoryEnumerator *fileEnumerator = [self.fileManager enumeratorAtPath:self.diskCachePath]; for (NSString *fileName in fileEnumerator) { @@ -214,7 +214,7 @@ return size; } -- (NSInteger)totalCount { +- (NSUInteger)totalCount { NSUInteger count = 0; NSDirectoryEnumerator *fileEnumerator = [self.fileManager enumeratorAtPath:self.diskCachePath]; count = fileEnumerator.allObjects.count; diff --git a/SDWebImage/SDImageCoder.h b/SDWebImage/SDImageCoder.h index 9084c6fb..36a78fb2 100644 --- a/SDWebImage/SDImageCoder.h +++ b/SDWebImage/SDImageCoder.h @@ -164,7 +164,7 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderWebImageContext; @return The animated image data */ -- (nullable NSData *)animatedImageData; +@property (nonatomic, copy, readonly, nullable) NSData *animatedImageData; /** Total animated frame count. @@ -172,13 +172,13 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderWebImageContext; @return Total animated frame count. */ -- (NSUInteger)animatedImageFrameCount; +@property (nonatomic, assign, readonly) NSUInteger animatedImageFrameCount; /** Animation loop count, 0 means infinite looping. @return Animation loop count */ -- (NSUInteger)animatedImageLoopCount; +@property (nonatomic, assign, readonly) NSUInteger animatedImageLoopCount; /** Returns the frame image from a specified index. @note The index maybe randomly if one image was set to different imageViews, keep it re-entrant. (It's not recommend to store the images into array because it's memory consuming) diff --git a/SDWebImage/SDImageTransformer.h b/SDWebImage/SDImageTransformer.h index a3e834ce..0a569ccc 100644 --- a/SDWebImage/SDImageTransformer.h +++ b/SDWebImage/SDImageTransformer.h @@ -32,7 +32,7 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab @return The cache key to appended after the original cache key. Should not be nil. */ -- (nonnull NSString *)transformerKey; +@property (nonatomic, copy, readonly, nonnull) NSString *transformerKey; /** Transform the image to another image. diff --git a/SDWebImage/SDWebImageDownloaderOperation.h b/SDWebImage/SDWebImageDownloaderOperation.h index f7f9f07e..01b7ea6d 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.h +++ b/SDWebImage/SDWebImageDownloaderOperation.h @@ -38,15 +38,13 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification - (BOOL)cancel:(nullable id)token; -- (nullable NSURLRequest *)request; -- (nullable NSURLResponse *)response; +@property (strong, nonatomic, readonly, nullable) NSURLRequest *request; +@property (strong, nonatomic, readonly, nullable) NSURLResponse *response; @optional -- (nullable NSURLSessionTask *)dataTask; -- (nullable NSURLCredential *)credential; -- (void)setCredential:(nullable NSURLCredential *)credential; -- (double)minimumProgressInterval; -- (void)setMinimumProgressInterval:(double)minimumProgressInterval; +@property (strong, nonatomic, readonly, nullable) NSURLSessionTask *dataTask; +@property (strong, nonatomic, nullable) NSURLCredential *credential; +@property (assign, nonatomic) double minimumProgressInterval; @end @@ -61,7 +59,7 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification /** * The response returned by the operation's task. */ -@property (strong, nonatomic, nullable, readonly) NSURLResponse *response; +@property (strong, nonatomic, readonly, nullable) NSURLResponse *response; /** * The operation's task @@ -73,7 +71,7 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification * * This will be overridden by any shared credentials that exist for the username or password of the request URL, if present. */ -@property (nonatomic, strong, nullable) NSURLCredential *credential; +@property (strong, nonatomic, nullable) NSURLCredential *credential; /** * The minimum interval about progress percent during network downloading. Which means the next progress callback and current progress callback's progress percent difference should be larger or equal to this value. However, the final finish download progress callback does not get effected. diff --git a/SDWebImage/SDWebImageIndicator.h b/SDWebImage/SDWebImageIndicator.h index aa62ca5f..9716dd90 100644 --- a/SDWebImage/SDWebImageIndicator.h +++ b/SDWebImage/SDWebImageIndicator.h @@ -20,7 +20,7 @@ @return The indicator view */ -- (nonnull UIView *)indicatorView; +@property (nonatomic, strong, readonly, nonnull) UIView *indicatorView; /** Start the animating for indicator. */ diff --git a/Tests/Tests/SDWebImageTestCache.m b/Tests/Tests/SDWebImageTestCache.m index da2a9935..1a92ec8f 100644 --- a/Tests/Tests/SDWebImageTestCache.m +++ b/Tests/Tests/SDWebImageTestCache.m @@ -91,11 +91,11 @@ [self.fileManager createFileAtPath:[self cachePathForKey:key] contents:data attributes:nil]; } -- (NSInteger)totalCount { +- (NSUInteger)totalCount { return [self.fileManager contentsOfDirectoryAtPath:self.cachePath error:nil].count; } -- (NSInteger)totalSize { +- (NSUInteger)totalSize { NSUInteger size = 0; for (NSString *fileName in [self.fileManager enumeratorAtPath:self.cachePath]) { NSString *filePath = [self.cachePath stringByAppendingPathComponent:fileName]; From 349bec44971d6c36d03d84da3ee92bca80706186 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 23 Aug 2018 15:35:38 +0800 Subject: [PATCH 257/361] Remove `sd_setAnimationImagesWithURLs` API, because its cause ambiguity, behave not consistently and have rare use case. --- SDWebImage/UIImageView+WebCache.h | 18 -------- SDWebImage/UIImageView+WebCache.m | 74 ------------------------------- 2 files changed, 92 deletions(-) diff --git a/SDWebImage/UIImageView+WebCache.h b/SDWebImage/UIImageView+WebCache.h index dabe4fcd..f84217e0 100644 --- a/SDWebImage/UIImageView+WebCache.h +++ b/SDWebImage/UIImageView+WebCache.h @@ -189,22 +189,4 @@ progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; -#if SD_UIKIT - -#pragma mark - Animation of multiple images - -/** - * Download an array of images and starts them in an animation loop - * - * @param arrayOfURLs An array of NSURL - */ -- (void)sd_setAnimationImagesWithURLs:(nonnull NSArray *)arrayOfURLs; - -/** - * Cancel the current animation images load - */ -- (void)sd_cancelCurrentAnimationImagesLoad; - -#endif - @end diff --git a/SDWebImage/UIImageView+WebCache.m b/SDWebImage/UIImageView+WebCache.m index 5d62e185..9d7f18e7 100644 --- a/SDWebImage/UIImageView+WebCache.m +++ b/SDWebImage/UIImageView+WebCache.m @@ -64,78 +64,4 @@ }]; } -#if SD_UIKIT - -#pragma mark - Animation of multiple images - -- (void)sd_setAnimationImagesWithURLs:(nonnull NSArray *)arrayOfURLs { - [self sd_cancelCurrentAnimationImagesLoad]; - NSPointerArray *operationsArray = [self sd_animationOperationArray]; - - [arrayOfURLs enumerateObjectsUsingBlock:^(NSURL *logoImageURL, NSUInteger idx, BOOL * _Nonnull stop) { - __weak __typeof(self) wself = self; - id operation = [[SDWebImageManager sharedManager] loadImageWithURL:logoImageURL options:0 progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { - __strong typeof(wself) sself = wself; - if (!sself) return; - dispatch_main_async_safe(^{ - [sself stopAnimating]; - if (sself && image) { - NSMutableArray *currentImages = [[sself animationImages] mutableCopy]; - if (!currentImages) { - currentImages = [[NSMutableArray alloc] init]; - } - - // We know what index objects should be at when they are returned so - // we will put the object at the index, filling any empty indexes - // with the image that was returned too "early". These images will - // be overwritten. (does not require additional sorting datastructure) - while ([currentImages count] < idx) { - [currentImages addObject:image]; - } - - currentImages[idx] = image; - - sself.animationImages = currentImages; - [sself setNeedsLayout]; - } - [sself startAnimating]; - }); - }]; - @synchronized (self) { - [operationsArray addPointer:(__bridge void *)(operation)]; - } - }]; -} - -static char animationLoadOperationKey; - -// element is weak because operation instance is retained by SDWebImageManager's runningOperations property -// we should use lock to keep thread-safe because these method may not be acessed from main queue -- (NSPointerArray *)sd_animationOperationArray { - @synchronized(self) { - NSPointerArray *operationsArray = objc_getAssociatedObject(self, &animationLoadOperationKey); - if (operationsArray) { - return operationsArray; - } - operationsArray = [NSPointerArray weakObjectsPointerArray]; - objc_setAssociatedObject(self, &animationLoadOperationKey, operationsArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - return operationsArray; - } -} - -- (void)sd_cancelCurrentAnimationImagesLoad { - NSPointerArray *operationsArray = [self sd_animationOperationArray]; - if (operationsArray) { - @synchronized (self) { - for (id operation in operationsArray) { - if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) { - [operation cancel]; - } - } - operationsArray.count = 0; - } - } -} -#endif - @end From 9afbc8bf7eb8799e7920d44e9a9e5614f9d10ae9 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 24 Aug 2018 15:54:04 +0800 Subject: [PATCH 258/361] Add no expiration file support of disk cache --- SDWebImage/SDDiskCache.m | 4 ++-- SDWebImage/SDImageCacheConfig.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/SDWebImage/SDDiskCache.m b/SDWebImage/SDDiskCache.m index 539cd68b..bcad109d 100644 --- a/SDWebImage/SDDiskCache.m +++ b/SDWebImage/SDDiskCache.m @@ -135,7 +135,7 @@ options:NSDirectoryEnumerationSkipsHiddenFiles errorHandler:NULL]; - NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.config.maxCacheAge]; + NSDate *expirationDate = (self.config.maxCacheAge < 0) ? nil: [NSDate dateWithTimeIntervalSinceNow:-self.config.maxCacheAge]; NSMutableDictionary *> *cacheFiles = [NSMutableDictionary dictionary]; NSUInteger currentCacheSize = 0; @@ -155,7 +155,7 @@ // Remove files that are older than the expiration date; NSDate *modifiedDate = resourceValues[cacheContentDateKey]; - if ([[modifiedDate laterDate:expirationDate] isEqualToDate:expirationDate]) { + if (expirationDate && [[modifiedDate laterDate:expirationDate] isEqualToDate:expirationDate]) { [urlsToDelete addObject:fileURL]; continue; } diff --git a/SDWebImage/SDImageCacheConfig.h b/SDWebImage/SDImageCacheConfig.h index 3ac6fc7c..8732eaec 100644 --- a/SDWebImage/SDImageCacheConfig.h +++ b/SDWebImage/SDImageCacheConfig.h @@ -68,13 +68,14 @@ typedef NS_ENUM(NSUInteger, SDImageCacheConfigExpireType) { @property (assign, nonatomic) NSDataWritingOptions diskCacheWritingOptions; /** - * The maximum length of time to keep an image in the cache, in seconds. + * The maximum length of time to keep an image in the disk cache, in seconds. + * Setting this to a negative value means no expiring. * Defaults to 1 weak. */ @property (assign, nonatomic) NSTimeInterval maxCacheAge; /** - * The maximum size of the cache, in bytes. + * The maximum size of the disk cache, in bytes. * Defaults to 0. Which means there is no cache size limit. */ @property (assign, nonatomic) NSUInteger maxCacheSize; From 1f3d83784cac857899cce09c759b19ef180268d4 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 24 Aug 2018 16:03:50 +0800 Subject: [PATCH 259/361] Fix resource key invalid when clean cached disk file --- SDWebImage/SDDiskCache.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDDiskCache.m b/SDWebImage/SDDiskCache.m index 539cd68b..bac439f7 100644 --- a/SDWebImage/SDDiskCache.m +++ b/SDWebImage/SDDiskCache.m @@ -177,10 +177,10 @@ // Target half of our maximum cache size for this cleanup pass. const NSUInteger desiredCacheSize = maxCacheSize / 2; - // Sort the remaining cache files by their last modification time (oldest first). + // Sort the remaining cache files by their last modification time or last access time (oldest first). NSArray *sortedFiles = [cacheFiles keysSortedByValueWithOptions:NSSortConcurrent usingComparator:^NSComparisonResult(id obj1, id obj2) { - return [obj1[NSURLContentModificationDateKey] compare:obj2[NSURLContentModificationDateKey]]; + return [obj1[cacheContentDateKey] compare:obj2[cacheContentDateKey]]; }]; // Delete files until we fall below our desired cache size. From 9bd5c051131172098e63a59385301c1812e74e68 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Tue, 28 Aug 2018 11:29:19 +0800 Subject: [PATCH 260/361] Add more detaild comments of maxCacheAge and fix typo --- SDWebImage/SDImageCacheConfig.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDImageCacheConfig.h b/SDWebImage/SDImageCacheConfig.h index 8732eaec..d7f86107 100644 --- a/SDWebImage/SDImageCacheConfig.h +++ b/SDWebImage/SDImageCacheConfig.h @@ -44,14 +44,14 @@ typedef NS_ENUM(NSUInteger, SDImageCacheConfigExpireType) { /* * The option to control weak memory cache for images. When enable, `SDImageCache`'s memory cache will use a weak maptable to store the image at the same time when it stored to memory, and get removed at the same time. - * However when memory warning is triggered, since the weak maptable does not hold a strong reference to image instacnce, even when the memory cache itself is purged, some images which are held strongly by UIImageViews or other live instances can be recovered again, to avoid later re-query from disk cache or network. This may be helpful for the case, for example, when app enter background and memory is purged, cause cell flashing after re-enter foreground. + * However when memory warning is triggered, since the weak maptable does not hold a strong reference to image instance, even when the memory cache itself is purged, some images which are held strongly by UIImageViews or other live instances can be recovered again, to avoid later re-query from disk cache or network. This may be helpful for the case, for example, when app enter background and memory is purged, cause cell flashing after re-enter foreground. * Defautls to YES. You can change this option dynamically. */ @property (assign, nonatomic) BOOL shouldUseWeakMemoryCache; /** * Whether or not to remove the expired disk data when application entering the background. (Not works for macOS) - * Defatuls to YES. + * Defaults to YES. */ @property (assign, nonatomic) BOOL shouldRemoveExpiredDataWhenEnterBackground; @@ -70,6 +70,7 @@ typedef NS_ENUM(NSUInteger, SDImageCacheConfigExpireType) { /** * The maximum length of time to keep an image in the disk cache, in seconds. * Setting this to a negative value means no expiring. + * Setting this to zero means that all cached files would be removed when do expiration check. * Defaults to 1 weak. */ @property (assign, nonatomic) NSTimeInterval maxCacheAge; From c99ddbfac99ffc69b3adb69c84ccd1ed313d8472 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 21 Aug 2018 12:48:40 +0800 Subject: [PATCH 261/361] Add one initializer with extra arg for custom animated image class to use possible coder options, to make it extensible --- SDWebImage/SDAnimatedImage.h | 15 +++++++++++++-- SDWebImage/SDAnimatedImage.m | 9 ++++++++- SDWebImage/SDAnimatedImageView.h | 2 +- SDWebImage/SDImageCacheDefine.m | 15 ++++++++------- SDWebImage/SDImageLoader.m | 30 ++++++++++++++++-------------- SDWebImage/SDWebImageDefine.h | 2 +- 6 files changed, 47 insertions(+), 26 deletions(-) diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h index 6ae98571..2112685a 100644 --- a/SDWebImage/SDAnimatedImage.h +++ b/SDWebImage/SDAnimatedImage.h @@ -16,9 +16,20 @@ @protocol SDAnimatedImage @required +/** + Initializes and returns the image object with the specified data, scale factor and possible animation decoding options. + @note We use this to create animated image instance for normal animation decoding. + + @param data The data object containing the image data. + @param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property. + @param options A dictionary containing any animation decoding options. + @return An initialized object + */ +- (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale options:(nullable SDImageCoderOptions *)options; + /** 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. However, for progressive image decoding, we will use this with animated coder which conforms to `SDProgressiveImageCoder` as well instead. + @note We use this with animated coder which conforms to `SDProgressiveImageCoder` for progressive animation decoding. @param animatedCoder An animated coder which conform `SDAnimatedImageCoder` protocol @param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property. @@ -27,6 +38,7 @@ - (nullable instancetype)initWithAnimatedCoder:(nonnull id)animatedCoder scale:(CGFloat)scale; @optional +// These methods are used for optional advanced feature, like image frame preloading. /** 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. @@ -63,7 +75,6 @@ - (nullable instancetype)initWithContentsOfFile:(nonnull NSString *)path; - (nullable instancetype)initWithData:(nonnull NSData *)data; - (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale; -- (nullable instancetype)initWithAnimatedCoder:(nonnull id)animatedCoder scale:(CGFloat)scale; /** Current animated image format. diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index fa20c898..2ad9b72e 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -276,6 +276,10 @@ static NSArray *SDBundlePreferredScales() { } - (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale { + return [self initWithData:data scale:scale options:nil]; +} + +- (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale options:(SDImageCoderOptions *)options { if (!data || data.length == 0) { return nil; } @@ -284,7 +288,10 @@ static NSArray *SDBundlePreferredScales() { for (idcoder in [SDImageCodersManager sharedManager].coders) { if ([coder conformsToProtocol:@protocol(SDAnimatedImageCoder)]) { if ([coder canDecodeFromData:data]) { - animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data options:@{SDImageCoderDecodeScaleFactor : @(scale)}]; + if (!options) { + options = @{SDImageCoderDecodeScaleFactor : @(scale)}; + } + animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data options:options]; break; } } diff --git a/SDWebImage/SDAnimatedImageView.h b/SDWebImage/SDAnimatedImageView.h index e822c4ea..ec5bda13 100644 --- a/SDWebImage/SDAnimatedImageView.h +++ b/SDWebImage/SDAnimatedImageView.h @@ -53,7 +53,7 @@ /** Whehter or not to enable incremental image load for animated image. This is for the animated image which `sd_isIncremental` is YES (See `UIImage+Metadata.h`). If enable, animated image rendering will stop at the last frame available currently, and continue when another `setImage:` trigger, where the new animated image's `animatedImageData` should be updated from the previous one. If the `sd_isIncremental` is NO. The incremental image load stop. @note If you are confused about this description, open Chrome browser to view some large GIF images with low network speed to see the animation behavior. - @note The best practice to use incremental load is using `initWithAnimatedCoder:scale` in `SDAnimatedImage` with animated coder which conform to `SDProgressiveImageCoder` as well. Then call incremental update and incremental decode method to produce the image. + @note The best practice to use incremental load is using `initWithAnimatedCoder:scale:` in `SDAnimatedImage` with animated coder which conform to `SDProgressiveImageCoder` as well. Then call incremental update and incremental decode method to produce the image. Default is YES. Set to NO to only render the static poster for incremental animated image. */ @property (nonatomic, assign) BOOL shouldIncrementalLoad; diff --git a/SDWebImage/SDImageCacheDefine.m b/SDWebImage/SDImageCacheDefine.m index 3bef6dbe..423e0583 100644 --- a/SDWebImage/SDImageCacheDefine.m +++ b/SDWebImage/SDImageCacheDefine.m @@ -20,23 +20,24 @@ UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSS if (scale < 1) { scale = 1; } + SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; + if (context) { + SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy]; + [mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext]; + coderOptions = [mutableCoderOptions copy]; + } + if (!decodeFirstFrame) { Class animatedImageClass = context[SDWebImageContextAnimatedImageClass]; // check whether we should use `SDAnimatedImage` if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { - image = [[animatedImageClass alloc] initWithData:imageData scale:scale]; + image = [[animatedImageClass alloc] initWithData:imageData scale:scale options:coderOptions]; if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { [((id)image) preloadAllFrames]; } } } if (!image) { - SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; - if (context) { - SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy]; - [mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext]; - coderOptions = [mutableCoderOptions copy]; - } image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:coderOptions]; } if (image) { diff --git a/SDWebImage/SDImageLoader.m b/SDWebImage/SDImageLoader.m index 87f6c84f..7d3db1a9 100644 --- a/SDWebImage/SDImageLoader.m +++ b/SDWebImage/SDImageLoader.m @@ -34,23 +34,24 @@ UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Nonnull imageData, NS if (scale < 1) { scale = 1; } + SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; + if (context) { + SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy]; + [mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext]; + coderOptions = [mutableCoderOptions copy]; + } + if (!decodeFirstFrame) { // check whether we should use `SDAnimatedImage` Class animatedImageClass = context[SDWebImageContextAnimatedImageClass]; if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { - image = [[animatedImageClass alloc] initWithData:imageData scale:scale]; + image = [[animatedImageClass alloc] initWithData:imageData scale:scale options:coderOptions]; if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { [((id)image) preloadAllFrames]; } } } if (!image) { - SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; - if (context) { - SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy]; - [mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext]; - coderOptions = [mutableCoderOptions copy]; - } image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:coderOptions]; } if (image) { @@ -95,13 +96,20 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im if (scale < 1) { scale = 1; } + SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; + if (context) { + SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy]; + [mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext]; + coderOptions = [mutableCoderOptions copy]; + } + id progressiveCoder = objc_getAssociatedObject(operation, SDImageLoaderProgressiveCoderKey); if (!progressiveCoder) { // We need to create a new instance for progressive decoding to avoid conflicts for (idcoder in [SDImageCodersManager sharedManager].coders.reverseObjectEnumerator) { if ([coder conformsToProtocol:@protocol(SDProgressiveImageCoder)] && [((id)coder) canIncrementalDecodeFromData:imageData]) { - progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:@{SDImageCoderDecodeScaleFactor : @(scale)}]; + progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:coderOptions]; break; } } @@ -121,12 +129,6 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im } } if (!image) { - SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; - if (context) { - SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy]; - [mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext]; - coderOptions = [mutableCoderOptions copy]; - } image = [progressiveCoder incrementalDecodedImageWithOptions:coderOptions]; } if (image) { diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index 15e25726..999c3b92 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -208,7 +208,7 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageS FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextStoreCacheType; /** - A Class object which the instance is a `UIImage/NSImage` subclass and adopt `SDAnimatedImage` protocol. We will call `initWithData:scale:` to create the instance (or `initWithAnimatedCoder:scale` when using progressive download) . If the instance create failed, fallback to normal `UIImage/NSImage`. + A Class object which the instance is a `UIImage/NSImage` subclass and adopt `SDAnimatedImage` protocol. We will call `initWithData:scale:options:` to create the instance (or `initWithAnimatedCoder:scale:` when using progressive download) . If the instance create failed, fallback to normal `UIImage/NSImage`. This can be used to improve animated images rendering performance (especially memory usage on big animated images) with `SDAnimatedImageView` (Class). */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextAnimatedImageClass; From 7c5c114aa597ce36808a5067adf8c09a6044c18f Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 28 Aug 2018 15:21:59 +0800 Subject: [PATCH 262/361] Update the comment about scale factor for coders --- SDWebImage/SDImageCoder.h | 3 +-- SDWebImage/SDWebImageManager.m | 4 ---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/SDWebImage/SDImageCoder.h b/SDWebImage/SDImageCoder.h index 36a78fb2..ff28a5cd 100644 --- a/SDWebImage/SDImageCoder.h +++ b/SDWebImage/SDImageCoder.h @@ -51,7 +51,6 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderWebImageContext; /** This is the image coder protocol to provide custom image decoding/encoding. These methods are all required to implement. - You do not need to specify image scale during decoding because we may scale image later. @note Pay attention that these methods are not called from main queue. */ @protocol SDImageCoder @@ -71,7 +70,7 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderWebImageContext; @note This protocol may supports decode animated image frames. You can use `+[SDImageCoderHelper animatedImageWithFrames:]` to produce an animated image with frames. @param data The image data to be decoded - @param options A dictionary containing any decoding options. Pass @{SDImageCoderDecodeFirstFrameOnly: @(YES)} to decode the first frame only. + @param options A dictionary containing any decoding options. Pass @{SDImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for image. Pass @{SDImageCoderDecodeFirstFrameOnly: @(YES)} to decode the first frame only. @return The decoded image from data */ - (nullable UIImage *)decodedImageWithData:(nullable NSData *)data diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 0cde8804..31f4145a 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -108,10 +108,6 @@ static id _defaultImageLoader; } } -- (nullable UIImage *)scaledImageForKey:(nullable NSString *)key image:(nullable UIImage *)image { - return SDScaledImageForKey(key, image); -} - - (SDWebImageCombinedOperation *)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDInternalCompletionBlock)completedBlock { return [self loadImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock]; } From 1ed0b8cfe86066ea28093406fcd859efd40c9d96 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Thu, 30 Aug 2018 13:27:39 +0300 Subject: [PATCH 263/361] Bumped version to 5.0.0-beta3 + updated CHANGELOG --- CHANGELOG.md | 25 +++++++++++++++++++++++++ SDWebImage.podspec | 2 +- WebImage/Info.plist | 4 ++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2604d83a..e647c8dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +## [5.0.0-beta3 - Customizable SDWebImage, on Aug 30th, 2018](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta3) +See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/milestone/15) + +#### Features +- Minimum progress interval config for `SDWebImageDownloader` #2415 #2437 1d8454d +- Feature disk cache migration from 4.x #2417 #2433 +- Add `SDImageFormatHEIF` represent `mif1` && `msf1` brands #2423 (imported from 4.4.3) +- Add default `HTTP User-Agent` for specific system #2409 (imported from 4.4.3) +- Replace `valueForKey` with `objectForKey` when access NSDictionary #2399 +- Improved unit tests #2438 #2434 +- Enhanced contributing guide #2416 +- Adopt all the protocol APIs which contains getter value to use property instead, to make the API easy to use or Swift user #2452 +- Remove `sd_setAnimationImagesWithURLs` API, because its cause ambiguity, behave not consistently and have rare use case #2459 +- Improved `SDAnimatedImage` protocol with `initWithData:scale:options:` #2453 +- Extra args for `SDSetImageBlock` (added `cacheType` and `imageURL`) #2449 + +#### Fixes +- Fix that using `NS_TYPED_ENUM` on `SDImageFormat` cause the existing Swift API (`sd_UTTypeFromImageFormat`) naming changed #2413 +- Fix that downloader options about image decoding is not correctly set #2414 +- Make download receive response notification only dispatch to specific observer #2426 +- Fix a race condition during progressive animation load in `SDAnimatedImageView` #2435 +- Fix the bug that `SDWebImageContextCacheKeyFilter` wrongly be used as cache serializer and cause crash #2451 +- Fix resource key invalid when clean cached disk file #2462 +- Add no expiration file support of disk cache #2461 + ## [5.0.0-beta2 - Customizable SDWebImage, on Jul 31st, 2018](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta2) See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/milestone/15) diff --git a/SDWebImage.podspec b/SDWebImage.podspec index cadc8034..5dcb72b4 100644 --- a/SDWebImage.podspec +++ b/SDWebImage.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'SDWebImage' - s.version = '5.0.0-beta2' + s.version = '5.0.0-beta3' s.osx.deployment_target = '10.10' s.ios.deployment_target = '8.0' diff --git a/WebImage/Info.plist b/WebImage/Info.plist index 20874b51..aed10d12 100644 --- a/WebImage/Info.plist +++ b/WebImage/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.0.0-beta2 + 5.0.0-beta3 CFBundleSignature ???? CFBundleVersion - 5.0.0-beta2 + 5.0.0-beta3 NSPrincipalClass From c76b9e3c2aff8a7eb12a53c096ad0b2d538ed058 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 30 Aug 2018 23:20:35 +0800 Subject: [PATCH 264/361] Add protect when custom animated image class image data is nil during progressive animation check --- SDWebImage/SDAnimatedImageView.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index 99bebeee..32db4476 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -626,6 +626,10 @@ static NSUInteger SDDeviceFreeMemory() { NSData *previousData = [((UIImage *)previousImage) animatedImageData]; NSData *currentData = [((UIImage *)image) animatedImageData]; // Check whether to use progressive rendering or not + if (!previousData || !currentData) { + // Early return + return; + } // Warning: normally the `previousData` is same instance as `currentData` because our `SDAnimatedImage` class share the same `coder` instance internally. But there may be a race condition, that later retrived `currentData` is already been updated and it's not the same instance as `previousData`. // And for protocol extensible design, we should not assume `SDAnimatedImage` protocol implementations always share same instance. So both of two reasons, we need that `rangeOfData` check. From 6d85cd9061a637d5eb210a405a09811e9a1d7648 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 31 Aug 2018 17:47:39 +0800 Subject: [PATCH 265/361] Decrease animated decode times when cache enable --- SDWebImage/SDAnimatedImageView.m | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index 32db4476..0e6c52fd 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -639,7 +639,7 @@ static NSUInteger SDDeviceFreeMemory() { } else if (currentData.length > previousData.length) { // If current data is appended by previous data, use `NSDataSearchAnchored` NSRange range = [currentData rangeOfData:previousData options:NSDataSearchAnchored range:NSMakeRange(0, previousData.length)]; - if (range.location == 0 && range.length == previousData.length) { + if (range.location == 0) { // Contains hole previous data and they start with the same beginning self.isProgressive = YES; } @@ -743,13 +743,19 @@ static NSUInteger SDDeviceFreeMemory() { // Or, most cases, the decode speed is faster than render speed, we fetch next frame fetchFrameIndex = nextFrameIndex; } - if (!bufferFull && self.fetchQueue.operationCount == 0) { + + UIImage *fetchFrame; + LOCKBLOCK({ + fetchFrame = self.frameBuffer[@(fetchFrameIndex)]; + }); + + if (!fetchFrame && !bufferFull && self.fetchQueue.operationCount == 0) { // Prefetch next frame in background queue UIImage *animatedImage = self.animatedImage; NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ - UIImage *fetchFrame = [animatedImage animatedImageFrameAtIndex:fetchFrameIndex]; + UIImage *frame = [animatedImage animatedImageFrameAtIndex:fetchFrameIndex]; LOCKBLOCK({ - self.frameBuffer[@(fetchFrameIndex)] = fetchFrame; + self.frameBuffer[@(fetchFrameIndex)] = frame; }); }]; [self.fetchQueue addOperation:operation]; From 759b7322c972e72cc3571b9adeae4b6fb62200cd Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 31 Aug 2018 21:53:53 +0800 Subject: [PATCH 266/361] Remove lock tradeoff when get fetchFrame --- SDWebImage/SDAnimatedImageView.m | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index 0e6c52fd..9c7d4595 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -689,8 +689,10 @@ static NSUInteger SDDeviceFreeMemory() { // Update the current frame UIImage *currentFrame; + UIImage *fetchFrame; LOCKBLOCK({ currentFrame = self.frameBuffer[@(currentFrameIndex)]; + fetchFrame = currentFrame ? self.frameBuffer[@(nextFrameIndex)] : nil; }); BOOL bufferFull = NO; if (currentFrame) { @@ -744,11 +746,6 @@ static NSUInteger SDDeviceFreeMemory() { fetchFrameIndex = nextFrameIndex; } - UIImage *fetchFrame; - LOCKBLOCK({ - fetchFrame = self.frameBuffer[@(fetchFrameIndex)]; - }); - if (!fetchFrame && !bufferFull && self.fetchQueue.operationCount == 0) { // Prefetch next frame in background queue UIImage *animatedImage = self.animatedImage; From 3dc5b0ab67e10d7d8c5be3f406598c6188ef46bb Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Mon, 3 Sep 2018 16:34:17 +0800 Subject: [PATCH 267/361] Change data compare statement when do animated data comparation --- SDWebImage/SDAnimatedImageView.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index 9c7d4595..b858aef6 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -637,9 +637,9 @@ static NSUInteger SDDeviceFreeMemory() { // If current data is the same data (or instance) as previous data self.isProgressive = YES; } else if (currentData.length > previousData.length) { - // If current data is appended by previous data, use `NSDataSearchAnchored` + // If current data is appended by previous data, use `NSDataSearchAnchored`, search is limited to start of currentData NSRange range = [currentData rangeOfData:previousData options:NSDataSearchAnchored range:NSMakeRange(0, previousData.length)]; - if (range.location == 0) { + if (range.location != NSNotFound) { // Contains hole previous data and they start with the same beginning self.isProgressive = YES; } From b1b48cca818f4d539d36921a7d2b844f2cb4beee Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 5 Sep 2018 22:07:34 +0800 Subject: [PATCH 268/361] Remove kCGImageSourceShouldCache option when create image source --- SDWebImage/SDImageAPNGCoder.m | 3 +-- SDWebImage/SDImageGIFCoder.m | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/SDWebImage/SDImageAPNGCoder.m b/SDWebImage/SDImageAPNGCoder.m index 8c58aa1b..64384122 100644 --- a/SDWebImage/SDImageAPNGCoder.m +++ b/SDWebImage/SDImageAPNGCoder.m @@ -326,8 +326,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef } self = [super init]; if (self) { - // use Image/IO cache because it's already keep a balance between CPU & memory - CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceShouldCache : @(YES)}); + CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); if (!imageSource) { return nil; } diff --git a/SDWebImage/SDImageGIFCoder.m b/SDWebImage/SDImageGIFCoder.m index 008a2b0b..2bea5b94 100644 --- a/SDWebImage/SDImageGIFCoder.m +++ b/SDWebImage/SDImageGIFCoder.m @@ -327,8 +327,7 @@ } self = [super init]; if (self) { - // use Image/IO cache because it's already keep a balance between CPU & memory - CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceShouldCache : @(YES)}); + CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); if (!imageSource) { return nil; } From 703631d51a339de3edb867eaf23039022fb4849d Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 7 Sep 2018 10:48:38 +0800 Subject: [PATCH 269/361] Add autoreleasepool to release autorelease objects in advance when using GCD --- SDWebImage/SDWebImageDownloaderOperation.m | 28 +++++++++-------- SDWebImage/SDWebImageManager.m | 36 ++++++++++++---------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 8bdfa27a..2a40af00 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -361,11 +361,13 @@ didReceiveResponse:(NSURLResponse *)response // progressive decode the image in coder queue dispatch_async(self.coderQueue, ^{ - UIImage *image = SDImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, finished, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); - if (image) { - // We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding. - - [self callCompletionBlocksWithImage:image imageData:nil error:nil finished:NO]; + @autoreleasepool { + UIImage *image = SDImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, finished, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); + if (image) { + // We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding. + + [self callCompletionBlocksWithImage:image imageData:nil error:nil finished:NO]; + } } }); } @@ -428,14 +430,16 @@ didReceiveResponse:(NSURLResponse *)response } else { // decode the image in coder queue dispatch_async(self.coderQueue, ^{ - UIImage *image = SDImageLoaderDecodeImageData(imageData, self.request.URL, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); - CGSize imageSize = image.size; - if (imageSize.width == 0 || imageSize.height == 0) { - [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorBadImageData userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}]]; - } else { - [self callCompletionBlocksWithImage:image imageData:imageData error:nil finished:YES]; + @autoreleasepool { + UIImage *image = SDImageLoaderDecodeImageData(imageData, self.request.URL, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); + CGSize imageSize = image.size; + if (imageSize.width == 0 || imageSize.height == 0) { + [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorBadImageData userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}]]; + } else { + [self callCompletionBlocksWithImage:image imageData:imageData error:nil finished:YES]; + } + [self done]; } - [self done]; }); } } else { diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 31f4145a..4f40307a 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -282,29 +282,33 @@ static id _defaultImageLoader; id cacheSerializer = context[SDWebImageContextCacheSerializer]; if (downloadedImage && (!downloadedImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage)) && transformer) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - UIImage *transformedImage = [transformer transformedImageWithImage:downloadedImage forKey:key]; - if (transformedImage && finished) { - NSString *transformerKey = [transformer transformerKey]; - NSString *cacheKey = SDTransformedKeyForKey(key, transformerKey); - BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage]; - NSData *cacheData; - // pass nil if the image was transformed, so we can recalculate the data from the image - if (cacheSerializer) { - cacheData = [cacheSerializer cacheDataWithImage:transformedImage originalData:(imageWasTransformed ? nil : downloadedData) imageURL:url]; - } else { - cacheData = (imageWasTransformed ? nil : downloadedData); + @autoreleasepool { + UIImage *transformedImage = [transformer transformedImageWithImage:downloadedImage forKey:key]; + if (transformedImage && finished) { + NSString *transformerKey = [transformer transformerKey]; + NSString *cacheKey = SDTransformedKeyForKey(key, transformerKey); + BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage]; + NSData *cacheData; + // pass nil if the image was transformed, so we can recalculate the data from the image + if (cacheSerializer) { + cacheData = [cacheSerializer cacheDataWithImage:transformedImage originalData:(imageWasTransformed ? nil : downloadedData) imageURL:url]; + } else { + cacheData = (imageWasTransformed ? nil : downloadedData); + } + [self.imageCache storeImage:transformedImage imageData:cacheData forKey:cacheKey cacheType:storeCacheType completion:nil]; } - [self.imageCache storeImage:transformedImage imageData:cacheData forKey:cacheKey cacheType:storeCacheType completion:nil]; + + [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; } - - [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; }); } else { if (downloadedImage && finished) { if (cacheSerializer) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - NSData *cacheData = [cacheSerializer cacheDataWithImage:downloadedImage originalData:downloadedData imageURL:url]; - [self.imageCache storeImage:downloadedImage imageData:cacheData forKey:key cacheType:storeCacheType completion:nil]; + @autoreleasepool { + NSData *cacheData = [cacheSerializer cacheDataWithImage:downloadedImage originalData:downloadedData imageURL:url]; + [self.imageCache storeImage:downloadedImage imageData:cacheData forKey:key cacheType:storeCacheType completion:nil]; + } }); } else { [self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key cacheType:storeCacheType completion:nil]; From 64123734c3a5a40f128b06cae8413c144b75d71a Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Wed, 29 Aug 2018 13:54:48 +0300 Subject: [PATCH 270/361] Move webp component (and libwebp dependency) to SDWebImage/SDWebImageWebPCoder - move the webp component + the libwebp dependency to SDWebImage/SDWebImageWebPCoder (including tests and demo) - Xcode 9.4 - instead of directly linking the Demos to the frameworks, using CocoaPods (`Examples/Podfile`). This allows using SDWebImage/SDWebImageWebPCoder into our examples so we keep the WebP demos - demos code cleanup and warnings resolved - all links from docs (README, Migration guide, CHANGELOG) are full links, so they work even from external pages (i.e. https://cocoapods.org/pods/SDWebImage). - added "Additional modules" section to README --- .gitmodules | 3 - .travis.yml | 4 + CHANGELOG.md | 2 +- Docs/SDWebImage-5.0-Migration-guide.md | 2 +- Examples/Podfile | 25 + .../SDWebImage Demo.xcodeproj/project.pbxproj | 466 ++-- .../xcschemes/SDWebImage OSX Demo.xcscheme | 4 +- .../xcschemes/SDWebImage TV Demo.xcscheme | 4 +- .../xcschemes/SDWebImage Watch Demo.xcscheme | 4 +- .../SDWebImage Demo/DetailViewController.m | 11 +- .../SDWebImage Demo/MasterViewController.m | 30 +- Examples/SDWebImage OSX Demo/ViewController.m | 3 + Examples/SDWebImage TV Demo/ViewController.m | 2 + .../InterfaceController.m | 2 + .../NotificationController.m | 22 - README.md | 58 +- SDWebImage.podspec | 16 +- SDWebImage.xcodeproj/project.pbxproj | 2336 +---------------- .../xcschemes/SDWebImage OSX.xcscheme | 4 +- .../xcschemes/SDWebImage iOS static.xcscheme | 4 +- .../xcschemes/SDWebImage iOS.xcscheme | 4 +- .../xcschemes/SDWebImage tvOS.xcscheme | 4 +- .../SDWebImage watchOS static.xcscheme | 4 +- .../xcschemes/SDWebImage watchOS.xcscheme | 4 +- .../contents.xcworkspacedata | 6 + .../xcschemes/SDWebImage iOS Demo.xcscheme | 4 +- SDWebImage/SDImageCodersManager.h | 6 +- SDWebImage/SDImageCodersManager.m | 6 - SDWebImage/SDWebImageDownloader.m | 4 - SDWebImage/WebP/SDImageWebPCoder.h | 23 - SDWebImage/WebP/SDImageWebPCoder.m | 827 ------ SDWebImage/WebP/UIImage+WebP.h | 27 - SDWebImage/WebP/UIImage+WebP.m | 25 - Tests/Podfile | 2 - .../project.pbxproj | 22 +- .../xcshareddata/xcschemes/Tests Mac.xcscheme | 8 +- .../xcshareddata/xcschemes/Tests.xcscheme | 8 +- Tests/Tests/Images/TestImageAnimated.webp | Bin 4764 -> 0 bytes Tests/Tests/Images/TestImageStatic.webp | Bin 30320 -> 0 bytes Tests/Tests/SDAnimatedImageTest.m | 21 +- Tests/Tests/SDCategoriesTests.m | 15 - Tests/Tests/SDImageCoderTests.m | 20 +- Tests/Tests/SDTestCase.h | 1 - Tests/Tests/SDTestCase.m | 1 - Tests/Tests/SDWebImageDownloaderTests.m | 28 - Vendors/libwebp | 1 - WebImage/SDWebImage.h | 6 - 47 files changed, 367 insertions(+), 3712 deletions(-) delete mode 100644 .gitmodules create mode 100644 Examples/Podfile delete mode 100644 SDWebImage/WebP/SDImageWebPCoder.h delete mode 100644 SDWebImage/WebP/SDImageWebPCoder.m delete mode 100644 SDWebImage/WebP/UIImage+WebP.h delete mode 100644 SDWebImage/WebP/UIImage+WebP.m delete mode 100644 Tests/Tests/Images/TestImageAnimated.webp delete mode 100644 Tests/Tests/Images/TestImageStatic.webp delete mode 160000 Vendors/libwebp diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index ce6396d4..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "Vendors/libwebp"] - path = Vendors/libwebp - url = https://github.com/webmproject/libwebp diff --git a/.travis.yml b/.travis.yml index bdc805da..96d36964 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,8 +37,12 @@ script: - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage tvOS' -sdk appletvsimulator -configuration Debug | xcpretty -c - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS' -sdk watchsimulator -configuration Debug | xcpretty -c + + - echo Clean DerivedData + - rm -rf ~/Library/Developer/Xcode/DerivedData - echo Build the Demo apps + - pod install --project-directory=Examples - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX Demo' -sdk macosx -configuration Debug | xcpretty -c - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 8' | xcpretty -c - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage TV Demo' -sdk appletvsimulator -configuration Debug | xcpretty -c diff --git a/CHANGELOG.md b/CHANGELOG.md index e647c8dc..1763d3ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,7 +61,7 @@ See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/ #### Backwards incompatible changes -See the [5.0 Migration Guide](Docs/SDWebImage-5.0-Migration-guide.md) for a list of comprehensive changes and the way to update your code +See the [5.0 Migration Guide](https://raw.githubusercontent.com/rs/SDWebImage/5.x/Docs/SDWebImage-5.0-Migration-guide.md) for a list of comprehensive changes and the way to update your code #### Features - Introduce `SDAnimatedImageView`, `SDAnimatedImage` and refactor the way we handle animated images #2140 diff --git a/Docs/SDWebImage-5.0-Migration-guide.md b/Docs/SDWebImage-5.0-Migration-guide.md index cac95da0..4ef9cf4c 100644 --- a/Docs/SDWebImage-5.0-Migration-guide.md +++ b/Docs/SDWebImage-5.0-Migration-guide.md @@ -215,5 +215,5 @@ In SDWebImage 5.0 we did a clean up of the API. We are using many modern Objecti - `sd_currentAlternateImageURL()` changed to `sd_currentAlternateImageURL` ### Full API Diff -For advanced user who need the detailed API diff, we provide the full diff in a HTML web page: [SDWebImage 5.0 API Diff](https://raw.githubusercontent.com/rs/SDWebImage/master/Docs/Diff/5.0/apidiff.html) +For advanced user who need the detailed API diff, we provide the full diff in a HTML web page: [SDWebImage 5.0 API Diff](https://raw.githubusercontent.com/rs/SDWebImage/5.x/Docs/API-Diff/5.0/apidiff.html) diff --git a/Examples/Podfile b/Examples/Podfile new file mode 100644 index 00000000..9d72e39b --- /dev/null +++ b/Examples/Podfile @@ -0,0 +1,25 @@ +source 'https://github.com/CocoaPods/Specs.git' + +use_frameworks! + +project 'SDWebImage Demo' +workspace '../SDWebImage' + +pod 'SDWebImage/Core', :path => '../' +pod 'SDWebImageWebPCoder', :git => 'https://github.com/SDWebImage/SDWebImageWebPCoder.git', :branch => 'master' + +target 'SDWebImage iOS Demo' do + platform :ios, '8.0' +end + +target 'SDWebImage OSX Demo' do + platform :osx, '10.10' +end + +target 'SDWebImage TV Demo' do + platform :tvos, '9.2' +end + +target 'SDWebImage Watch Demo Extension' do + platform :watchos, '2.0' +end diff --git a/Examples/SDWebImage Demo.xcodeproj/project.pbxproj b/Examples/SDWebImage Demo.xcodeproj/project.pbxproj index 70bc067c..325e3114 100644 --- a/Examples/SDWebImage Demo.xcodeproj/project.pbxproj +++ b/Examples/SDWebImage Demo.xcodeproj/project.pbxproj @@ -7,17 +7,11 @@ objects = { /* Begin PBXBuildFile section */ - 327E2DCD1FAF0D6A00EF52C2 /* SDWebImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43A0FAAF1BDD16AC00B7582B /* SDWebImage.framework */; }; - 327E2DCE1FAF0D6A00EF52C2 /* SDWebImage.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 43A0FAAF1BDD16AC00B7582B /* SDWebImage.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 327E2DD21FAF0D7000EF52C2 /* SDWebImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43A629E71D0DFD000089D7DD /* SDWebImage.framework */; }; - 327E2DD31FAF0D7000EF52C2 /* SDWebImage.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 43A629E71D0DFD000089D7DD /* SDWebImage.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 327E2DD71FAF0D7900EF52C2 /* SDWebImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4397D2751D0DDBE100BB2784 /* SDWebImage.framework */; }; - 327E2DD81FAF0D7900EF52C2 /* SDWebImage.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4397D2751D0DDBE100BB2784 /* SDWebImage.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 327E2DDC1FAF0D8000EF52C2 /* SDWebImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 431739601CDFCC370008FEB9 /* SDWebImage.framework */; }; - 327E2DDD1FAF0D8000EF52C2 /* SDWebImage.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 431739601CDFCC370008FEB9 /* SDWebImage.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 1DFFF782AC680AB174A297D2 /* Pods_SDWebImage_Watch_Demo_Extension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C2FAC73C40132154E469AC8 /* Pods_SDWebImage_Watch_Demo_Extension.framework */; }; 32892E311FAE898C00BE8320 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 32892E301FAE898C00BE8320 /* Assets.xcassets */; }; 32892E351FAE89FE00BE8320 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 32892E341FAE89FD00BE8320 /* LaunchScreen.storyboard */; }; 3E75A9861742DBE700DA412D /* CustomPathImages in Resources */ = {isa = PBXBuildFile; fileRef = 3E75A9851742DBE700DA412D /* CustomPathImages */; }; + 3EB94398122E15A03521242D /* Pods_SDWebImage_iOS_Demo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E1C7793F375A90B31F03087 /* Pods_SDWebImage_iOS_Demo.framework */; }; 4314D1AA1D0E1181004B36C9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4314D1A91D0E1181004B36C9 /* main.m */; }; 4314D1AD1D0E1181004B36C9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4314D1AC1D0E1181004B36C9 /* AppDelegate.m */; }; 4314D1B01D0E1182004B36C9 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4314D1AF1D0E1182004B36C9 /* ViewController.m */; }; @@ -46,101 +40,12 @@ 537612B0155AB74D005750A4 /* DetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 537612AF155AB74D005750A4 /* DetailViewController.m */; }; 537612B3155AB74D005750A4 /* MasterViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 537612B1155AB74D005750A4 /* MasterViewController.xib */; }; 537612B6155AB74D005750A4 /* DetailViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 537612B4155AB74D005750A4 /* DetailViewController.xib */; }; + A335B6482715CD923F929224 /* Pods_SDWebImage_OSX_Demo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AFF4102E3D959CBB4FA13AB0 /* Pods_SDWebImage_OSX_Demo.framework */; }; + AB731AD9445BC0E9EA4F353C /* Pods_SDWebImage_TV_Demo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92719CCA7C38F5667B582562 /* Pods_SDWebImage_TV_Demo.framework */; }; DA248D44195470FD00390AB0 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 537612E3155ABA3C005750A4 /* MapKit.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 327E2DAE1FAF0A6B00EF52C2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 431BB6891D06D2C1006A3455; - remoteInfo = "SDWebImage watchOS"; - }; - 327E2DB31FAF0B3800EF52C2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 4A2CADFE1AB4BB5300B6BC39; - remoteInfo = "SDWebImage iOS"; - }; - 327E2DCF1FAF0D6A00EF52C2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 4A2CADFE1AB4BB5300B6BC39; - remoteInfo = "SDWebImage iOS"; - }; - 327E2DD41FAF0D7000EF52C2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 4397D2761D0DDD8C00BB2784; - remoteInfo = "SDWebImage OSX"; - }; - 327E2DD91FAF0D7900EF52C2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 431BB6891D06D2C1006A3455; - remoteInfo = "SDWebImage watchOS"; - }; - 327E2DDE1FAF0D8000EF52C2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 00733A4B1BC487C000A5A117; - remoteInfo = "SDWebImage tvOS"; - }; - 4314D19D1D0E0EB6004B36C9 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 4314D1991D0E0E3B004B36C9; - remoteInfo = "SDWebImage watchOS static"; - }; - 4314D1BA1D0E11A0004B36C9 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 00733A4B1BC487C000A5A117; - remoteInfo = "SDWebImage tvOS"; - }; - 4317395F1CDFCC370008FEB9 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 00733A4C1BC487C000A5A117; - remoteInfo = "WebImage tvOS"; - }; - 4397D2741D0DDBE100BB2784 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 431BB7031D06D2C1006A3455; - remoteInfo = "SDWebImage watchOS"; - }; - 43A0FAAE1BDD16AC00B7582B /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 4A2CADFF1AB4BB5300B6BC39; - remoteInfo = WebImage; - }; - 43A629E61D0DFD000089D7DD /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 4397D2F21D0DDD8C00BB2784; - remoteInfo = "SDWebImage OSX"; - }; - 43A629E91D0DFDCA0089D7DD /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 4397D2761D0DDD8C00BB2784; - remoteInfo = "SDWebImage OSX"; - }; 43A629FC1D0E07600089D7DD /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 5376128C155AB74D005750A4 /* Project object */; @@ -155,13 +60,6 @@ remoteGlobalIDString = 43A629ED1D0E07600089D7DD; remoteInfo = "SDWebImage Watch Demo"; }; - DA248D731954841D00390AB0 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 53761325155AD0D5005750A4; - remoteInfo = SDWebImage; - }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -171,7 +69,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 327E2DCE1FAF0D6A00EF52C2 /* SDWebImage.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -182,7 +79,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 327E2DD31FAF0D7000EF52C2 /* SDWebImage.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -193,7 +89,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 327E2DD81FAF0D7900EF52C2 /* SDWebImage.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -204,7 +99,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 327E2DDD1FAF0D8000EF52C2 /* SDWebImage.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -234,8 +128,14 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0A5C1B2C88218143A5BCB306 /* Pods-SDWebImage OSX Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage OSX Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo.debug.xcconfig"; sourceTree = ""; }; + 1E1C7793F375A90B31F03087 /* Pods_SDWebImage_iOS_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImage_iOS_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1E3938BD7F1865D9C3421374 /* Pods-SDWebImage iOS Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage iOS Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo.debug.xcconfig"; sourceTree = ""; }; + 201B6D833246D81FC96576AF /* Pods_SDWebImage_Watch_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImage_Watch_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3027DFFB4B050C9E195FC1E6 /* Pods-SDWebImage TV Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage TV Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo.release.xcconfig"; sourceTree = ""; }; 32892E301FAE898C00BE8320 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 32892E341FAE89FD00BE8320 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 3C2FAC73C40132154E469AC8 /* Pods_SDWebImage_Watch_Demo_Extension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImage_Watch_Demo_Extension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3E75A9851742DBE700DA412D /* CustomPathImages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = CustomPathImages; sourceTree = SOURCE_ROOT; }; 4314D1A61D0E1181004B36C9 /* SDWebImage TV Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SDWebImage TV Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 4314D1A91D0E1181004B36C9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; @@ -286,7 +186,13 @@ 537612B5155AB74D005750A4 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/DetailViewController.xib; sourceTree = ""; }; 537612E3155ABA3C005750A4 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; 537612E6155ABA44005750A4 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; - DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SDWebImage.xcodeproj; path = ../SDWebImage.xcodeproj; sourceTree = ""; }; + 92719CCA7C38F5667B582562 /* Pods_SDWebImage_TV_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImage_TV_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9B2818BFAE3E61037805BB0A /* Pods-SDWebImage Watch Demo Extension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage Watch Demo Extension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension.debug.xcconfig"; sourceTree = ""; }; + AFF4102E3D959CBB4FA13AB0 /* Pods_SDWebImage_OSX_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImage_OSX_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C78C49F71ED2172D9252509F /* Pods-SDWebImage iOS Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage iOS Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo.release.xcconfig"; sourceTree = ""; }; + CC928213A59B58D86A2040DD /* Pods-SDWebImage TV Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage TV Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo.debug.xcconfig"; sourceTree = ""; }; + E0B6B3418BA8A3EA9217E79A /* Pods-SDWebImage Watch Demo Extension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage Watch Demo Extension.release.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension.release.xcconfig"; sourceTree = ""; }; + FF1B0E74870E1C8DD6DBF631 /* Pods-SDWebImage OSX Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage OSX Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -294,7 +200,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 327E2DDC1FAF0D8000EF52C2 /* SDWebImage.framework in Frameworks */, + AB731AD9445BC0E9EA4F353C /* Pods_SDWebImage_TV_Demo.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -302,7 +208,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 327E2DD21FAF0D7000EF52C2 /* SDWebImage.framework in Frameworks */, + A335B6482715CD923F929224 /* Pods_SDWebImage_OSX_Demo.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -310,7 +216,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 327E2DD71FAF0D7900EF52C2 /* SDWebImage.framework in Frameworks */, + 1DFFF782AC680AB174A297D2 /* Pods_SDWebImage_Watch_Demo_Extension.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -322,8 +228,15 @@ 531041C1157EAC8F00BBABC3 /* ImageIO.framework in Frameworks */, 5376129A155AB74D005750A4 /* UIKit.framework in Frameworks */, 5376129C155AB74D005750A4 /* Foundation.framework in Frameworks */, - 327E2DCD1FAF0D6A00EF52C2 /* SDWebImage.framework in Frameworks */, 5376129E155AB74D005750A4 /* CoreGraphics.framework in Frameworks */, + 3EB94398122E15A03521242D /* Pods_SDWebImage_iOS_Demo.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A3F8A0092FB9960BF0FFE3E0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( ); runOnlyForDeploymentPostprocessing = 0; }; @@ -413,7 +326,6 @@ 5376128A155AB74D005750A4 = { isa = PBXGroup; children = ( - DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */, 5376129F155AB74D005750A4 /* SDWebImage Demo */, 43A629D01D0DFD000089D7DD /* SDWebImage OSX Demo */, 43A629EF1D0E07600089D7DD /* SDWebImage Watch Demo */, @@ -421,6 +333,7 @@ 4314D1A71D0E1181004B36C9 /* SDWebImage TV Demo */, 53761298155AB74D005750A4 /* Frameworks */, 53761296155AB74D005750A4 /* Products */, + C5D3D7AE3B6CBC7C43AE7833 /* Pods */, ); sourceTree = ""; }; @@ -444,6 +357,11 @@ 53761299155AB74D005750A4 /* UIKit.framework */, 5376129B155AB74D005750A4 /* Foundation.framework */, 5376129D155AB74D005750A4 /* CoreGraphics.framework */, + 1E1C7793F375A90B31F03087 /* Pods_SDWebImage_iOS_Demo.framework */, + AFF4102E3D959CBB4FA13AB0 /* Pods_SDWebImage_OSX_Demo.framework */, + 201B6D833246D81FC96576AF /* Pods_SDWebImage_Watch_Demo.framework */, + 92719CCA7C38F5667B582562 /* Pods_SDWebImage_TV_Demo.framework */, + 3C2FAC73C40132154E469AC8 /* Pods_SDWebImage_Watch_Demo_Extension.framework */, ); name = Frameworks; sourceTree = ""; @@ -477,17 +395,19 @@ name = "Supporting Files"; sourceTree = ""; }; - DA248D6D1954841D00390AB0 /* Products */ = { + C5D3D7AE3B6CBC7C43AE7833 /* Pods */ = { isa = PBXGroup; children = ( - DA248D741954841D00390AB0 /* libSDWebImage iOS static.a */, - 4314D19E1D0E0EB6004B36C9 /* libSDWebImage watchOS static.a */, - 43A0FAAF1BDD16AC00B7582B /* SDWebImage.framework */, - 431739601CDFCC370008FEB9 /* SDWebImage.framework */, - 4397D2751D0DDBE100BB2784 /* SDWebImage.framework */, - 43A629E71D0DFD000089D7DD /* SDWebImage.framework */, + 1E3938BD7F1865D9C3421374 /* Pods-SDWebImage iOS Demo.debug.xcconfig */, + C78C49F71ED2172D9252509F /* Pods-SDWebImage iOS Demo.release.xcconfig */, + 0A5C1B2C88218143A5BCB306 /* Pods-SDWebImage OSX Demo.debug.xcconfig */, + FF1B0E74870E1C8DD6DBF631 /* Pods-SDWebImage OSX Demo.release.xcconfig */, + CC928213A59B58D86A2040DD /* Pods-SDWebImage TV Demo.debug.xcconfig */, + 3027DFFB4B050C9E195FC1E6 /* Pods-SDWebImage TV Demo.release.xcconfig */, + 9B2818BFAE3E61037805BB0A /* Pods-SDWebImage Watch Demo Extension.debug.xcconfig */, + E0B6B3418BA8A3EA9217E79A /* Pods-SDWebImage Watch Demo Extension.release.xcconfig */, ); - name = Products; + name = Pods; sourceTree = ""; }; /* End PBXGroup section */ @@ -497,16 +417,16 @@ isa = PBXNativeTarget; buildConfigurationList = 4314D1B71D0E1182004B36C9 /* Build configuration list for PBXNativeTarget "SDWebImage TV Demo" */; buildPhases = ( + C1A2E0ED98B257BB14D9BD35 /* [CP] Check Pods Manifest.lock */, 4314D1A21D0E1181004B36C9 /* Sources */, 4314D1A31D0E1181004B36C9 /* Frameworks */, 4314D1A41D0E1181004B36C9 /* Resources */, 327E2DE01FAF0D8000EF52C2 /* Embed Frameworks */, + 30CA4D7A6B97CD11FB023FCD /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( - 4314D1BB1D0E11A0004B36C9 /* PBXTargetDependency */, - 327E2DDF1FAF0D8000EF52C2 /* PBXTargetDependency */, ); name = "SDWebImage TV Demo"; productName = "SDWebImage TV Demo"; @@ -517,16 +437,16 @@ isa = PBXNativeTarget; buildConfigurationList = 43A629E81D0DFD000089D7DD /* Build configuration list for PBXNativeTarget "SDWebImage OSX Demo" */; buildPhases = ( + E6792144F5EDB318B9B3E808 /* [CP] Check Pods Manifest.lock */, 43A629CB1D0DFD000089D7DD /* Sources */, 43A629CC1D0DFD000089D7DD /* Frameworks */, 43A629CD1D0DFD000089D7DD /* Resources */, 327E2DD61FAF0D7000EF52C2 /* Embed Frameworks */, + D3795F96D778EA0D160C99E0 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( - 43A629EA1D0DFDCA0089D7DD /* PBXTargetDependency */, - 327E2DD51FAF0D7000EF52C2 /* PBXTargetDependency */, ); name = "SDWebImage OSX Demo"; productName = "SDWebImage OSX Demo"; @@ -539,6 +459,7 @@ buildPhases = ( 43A629EC1D0E07600089D7DD /* Resources */, 43A62A131D0E07600089D7DD /* Embed App Extensions */, + A3F8A0092FB9960BF0FFE3E0 /* Frameworks */, ); buildRules = ( ); @@ -554,16 +475,16 @@ isa = PBXNativeTarget; buildConfigurationList = 43A62A101D0E07600089D7DD /* Build configuration list for PBXNativeTarget "SDWebImage Watch Demo Extension" */; buildPhases = ( + 845ACCC963F0540C3714E294 /* [CP] Check Pods Manifest.lock */, 43A629F61D0E07600089D7DD /* Sources */, 43A629F71D0E07600089D7DD /* Frameworks */, 43A629F81D0E07600089D7DD /* Resources */, 327E2DDB1FAF0D7A00EF52C2 /* Embed Frameworks */, + D108C032EF2001F3466266B0 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( - 327E2DAF1FAF0A6B00EF52C2 /* PBXTargetDependency */, - 327E2DDA1FAF0D7900EF52C2 /* PBXTargetDependency */, ); name = "SDWebImage Watch Demo Extension"; productName = "SDWebImage Watch Demo Extension"; @@ -574,18 +495,18 @@ isa = PBXNativeTarget; buildConfigurationList = 537612B9155AB74D005750A4 /* Build configuration list for PBXNativeTarget "SDWebImage iOS Demo" */; buildPhases = ( + C4617CE0275D471FCDB0F0BF /* [CP] Check Pods Manifest.lock */, 53761291155AB74D005750A4 /* Sources */, 53761292155AB74D005750A4 /* Frameworks */, 53761293155AB74D005750A4 /* Resources */, 43A62A171D0E07600089D7DD /* Embed Watch Content */, 327E2DD11FAF0D6A00EF52C2 /* Embed Frameworks */, + AEB35AD7EBE9525CAF4048E9 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( 43A62A0E1D0E07600089D7DD /* PBXTargetDependency */, - 327E2DB41FAF0B3800EF52C2 /* PBXTargetDependency */, - 327E2DD01FAF0D6A00EF52C2 /* PBXTargetDependency */, ); name = "SDWebImage iOS Demo"; productName = "SDWebImage Demo"; @@ -598,7 +519,7 @@ 5376128C155AB74D005750A4 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0900; + LastUpgradeCheck = 0940; ORGANIZATIONNAME = Dailymotion; TargetAttributes = { 4314D1A51D0E1181004B36C9 = { @@ -626,12 +547,6 @@ mainGroup = 5376128A155AB74D005750A4; productRefGroup = 53761296155AB74D005750A4 /* Products */; projectDirPath = ""; - projectReferences = ( - { - ProductGroup = DA248D6D1954841D00390AB0 /* Products */; - ProjectRef = DA248D6C1954841D00390AB0 /* SDWebImage.xcodeproj */; - }, - ); projectRoot = ""; targets = ( 53761294155AB74D005750A4 /* SDWebImage iOS Demo */, @@ -643,51 +558,6 @@ }; /* End PBXProject section */ -/* Begin PBXReferenceProxy section */ - 4314D19E1D0E0EB6004B36C9 /* libSDWebImage watchOS static.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libSDWebImage watchOS static.a"; - remoteRef = 4314D19D1D0E0EB6004B36C9 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 431739601CDFCC370008FEB9 /* SDWebImage.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = SDWebImage.framework; - remoteRef = 4317395F1CDFCC370008FEB9 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 4397D2751D0DDBE100BB2784 /* SDWebImage.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = SDWebImage.framework; - remoteRef = 4397D2741D0DDBE100BB2784 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 43A0FAAF1BDD16AC00B7582B /* SDWebImage.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = SDWebImage.framework; - remoteRef = 43A0FAAE1BDD16AC00B7582B /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 43A629E71D0DFD000089D7DD /* SDWebImage.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = SDWebImage.framework; - remoteRef = 43A629E61D0DFD000089D7DD /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - DA248D741954841D00390AB0 /* libSDWebImage iOS static.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libSDWebImage iOS static.a"; - remoteRef = DA248D731954841D00390AB0 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - /* Begin PBXResourcesBuildPhase section */ 4314D1A41D0E1181004B36C9 /* Resources */ = { isa = PBXResourcesBuildPhase; @@ -738,6 +608,177 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 30CA4D7A6B97CD11FB023FCD /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/SDWebImage-tvOS/SDWebImage.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder-tvOS/SDWebImageWebPCoder.framework", + "${BUILT_PRODUCTS_DIR}/libwebp-tvOS/libwebp.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 845ACCC963F0540C3714E294 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-SDWebImage Watch Demo Extension-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + AEB35AD7EBE9525CAF4048E9 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/SDWebImage-iOS/SDWebImage.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder-iOS/SDWebImageWebPCoder.framework", + "${BUILT_PRODUCTS_DIR}/libwebp-iOS/libwebp.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + C1A2E0ED98B257BB14D9BD35 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-SDWebImage TV Demo-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + C4617CE0275D471FCDB0F0BF /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-SDWebImage iOS Demo-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + D108C032EF2001F3466266B0 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/SDWebImage-watchOS/SDWebImage.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder-watchOS/SDWebImageWebPCoder.framework", + "${BUILT_PRODUCTS_DIR}/libwebp-watchOS/libwebp.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + ); + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + D3795F96D778EA0D160C99E0 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/SDWebImage-macOS/SDWebImage.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder-macOS/SDWebImageWebPCoder.framework", + "${BUILT_PRODUCTS_DIR}/libwebp-macOS/libwebp.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + E6792144F5EDB318B9B3E808 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-SDWebImage OSX Demo-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 4314D1A21D0E1181004B36C9 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -783,46 +824,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 327E2DAF1FAF0A6B00EF52C2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "SDWebImage watchOS"; - targetProxy = 327E2DAE1FAF0A6B00EF52C2 /* PBXContainerItemProxy */; - }; - 327E2DB41FAF0B3800EF52C2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "SDWebImage iOS"; - targetProxy = 327E2DB31FAF0B3800EF52C2 /* PBXContainerItemProxy */; - }; - 327E2DD01FAF0D6A00EF52C2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "SDWebImage iOS"; - targetProxy = 327E2DCF1FAF0D6A00EF52C2 /* PBXContainerItemProxy */; - }; - 327E2DD51FAF0D7000EF52C2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "SDWebImage OSX"; - targetProxy = 327E2DD41FAF0D7000EF52C2 /* PBXContainerItemProxy */; - }; - 327E2DDA1FAF0D7900EF52C2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "SDWebImage watchOS"; - targetProxy = 327E2DD91FAF0D7900EF52C2 /* PBXContainerItemProxy */; - }; - 327E2DDF1FAF0D8000EF52C2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "SDWebImage tvOS"; - targetProxy = 327E2DDE1FAF0D8000EF52C2 /* PBXContainerItemProxy */; - }; - 4314D1BB1D0E11A0004B36C9 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "SDWebImage tvOS"; - targetProxy = 4314D1BA1D0E11A0004B36C9 /* PBXContainerItemProxy */; - }; - 43A629EA1D0DFDCA0089D7DD /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "SDWebImage OSX"; - targetProxy = 43A629E91D0DFDCA0089D7DD /* PBXContainerItemProxy */; - }; 43A629FD1D0E07600089D7DD /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 43A629F91D0E07600089D7DD /* SDWebImage Watch Demo Extension */; @@ -881,6 +882,7 @@ /* Begin XCBuildConfiguration section */ 4314D1B81D0E1182004B36C9 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = CC928213A59B58D86A2040DD /* Pods-SDWebImage TV Demo.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; @@ -920,6 +922,7 @@ }; 4314D1B91D0E1182004B36C9 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 3027DFFB4B050C9E195FC1E6 /* Pods-SDWebImage TV Demo.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; @@ -961,6 +964,7 @@ }; 43A629E01D0DFD000089D7DD /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 0A5C1B2C88218143A5BCB306 /* Pods-SDWebImage OSX Demo.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ANALYZER_NONNULL = YES; @@ -1000,6 +1004,7 @@ }; 43A629E11D0DFD000089D7DD /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = FF1B0E74870E1C8DD6DBF631 /* Pods-SDWebImage OSX Demo.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ANALYZER_NONNULL = YES; @@ -1041,6 +1046,7 @@ }; 43A62A111D0E07600089D7DD /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 9B2818BFAE3E61037805BB0A /* Pods-SDWebImage Watch Demo Extension.debug.xcconfig */; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ANALYZER_NONNULL = YES; @@ -1080,6 +1086,7 @@ }; 43A62A121D0E07600089D7DD /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = E0B6B3418BA8A3EA9217E79A /* Pods-SDWebImage Watch Demo Extension.release.xcconfig */; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ANALYZER_NONNULL = YES; @@ -1208,11 +1215,13 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; @@ -1252,11 +1261,13 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; @@ -1282,6 +1293,7 @@ }; 537612BA155AB74D005750A4 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 1E3938BD7F1865D9C3421374 /* Pods-SDWebImage iOS Demo.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; @@ -1292,7 +1304,6 @@ ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "SDWebImage Demo/SDWebImage Demo-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; HEADER_SEARCH_PATHS = ( "\"$(OBJROOT)/UninstalledProducts/include\"", "\"$(TARGET_BUILD_DIR)/usr/local/lib/include\"", @@ -1300,8 +1311,6 @@ INFOPLIST_FILE = "SDWebImage Demo/SDWebImage Demo-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -1311,6 +1320,7 @@ }; 537612BB155AB74D005750A4 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = C78C49F71ED2172D9252509F /* Pods-SDWebImage iOS Demo.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; @@ -1321,7 +1331,6 @@ ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "SDWebImage Demo/SDWebImage Demo-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ""; HEADER_SEARCH_PATHS = ( "\"$(OBJROOT)/UninstalledProducts/include\"", "\"$(TARGET_BUILD_DIR)/usr/local/lib/include\"", @@ -1329,7 +1338,6 @@ INFOPLIST_FILE = "SDWebImage Demo/SDWebImage Demo-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; diff --git a/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX Demo.xcscheme b/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX Demo.xcscheme index c0915c9f..29c6338d 100644 --- a/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX Demo.xcscheme +++ b/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX Demo.xcscheme @@ -1,6 +1,6 @@ @@ -46,7 +45,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage TV Demo.xcscheme b/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage TV Demo.xcscheme index 07dc4c0c..483fe83a 100644 --- a/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage TV Demo.xcscheme +++ b/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage TV Demo.xcscheme @@ -1,6 +1,6 @@ @@ -46,7 +45,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage Watch Demo.xcscheme b/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage Watch Demo.xcscheme index 7b6f8fb5..9d21f33d 100644 --- a/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage Watch Demo.xcscheme +++ b/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage Watch Demo.xcscheme @@ -1,6 +1,6 @@ @@ -74,7 +73,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Examples/SDWebImage Demo/DetailViewController.m b/Examples/SDWebImage Demo/DetailViewController.m index e040e3d8..1ae344f8 100644 --- a/Examples/SDWebImage Demo/DetailViewController.m +++ b/Examples/SDWebImage Demo/DetailViewController.m @@ -17,8 +17,7 @@ @implementation DetailViewController -- (void)configureView -{ +- (void)configureView { if (!self.imageView.sd_imageIndicator) { self.imageView.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator; } @@ -27,15 +26,9 @@ options:SDWebImageProgressiveLoad]; } -- (void)viewDidLoad -{ +- (void)viewDidLoad { [super viewDidLoad]; [self configureView]; } -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); -} - @end diff --git a/Examples/SDWebImage Demo/MasterViewController.m b/Examples/SDWebImage Demo/MasterViewController.m index bb94f078..e32cf91f 100644 --- a/Examples/SDWebImage Demo/MasterViewController.m +++ b/Examples/SDWebImage Demo/MasterViewController.m @@ -9,6 +9,7 @@ #import "MasterViewController.h" #import "DetailViewController.h" #import +#import @interface MyCustomTableViewCell : UITableViewCell @@ -42,17 +43,17 @@ @implementation MasterViewController -- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil -{ +- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - if (self) - { + if (self) { self.title = @"SDWebImage"; self.navigationItem.rightBarButtonItem = [UIBarButtonItem.alloc initWithTitle:@"Clear Cache" style:UIBarButtonItemStylePlain target:self action:@selector(flushCache)]; + [[SDImageCodersManager sharedManager] addCoder:[SDImageWebPCoder sharedCoder]]; + // HTTP NTLM auth example // Add your NTLM image url to the array below and replace the credentials [SDWebImageDownloader sharedDownloader].config.username = @"httpwatch"; @@ -78,35 +79,25 @@ for (int i=0; i<100; i++) { [self.objects addObject:[NSString stringWithFormat:@"https://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage%03d.jpg", i]]; } - } return self; } -- (void)flushCache -{ +- (void)flushCache { [SDWebImageManager.sharedManager.imageCache clearWithCacheType:SDImageCacheTypeAll completion:nil]; } - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); -} #pragma mark - Table View -- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView -{ +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section -{ +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.objects.count; } -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; static UIImage *placeholderImage = nil; @@ -128,8 +119,7 @@ return cell; } -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath -{ +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSString *largeImageURLString = [self.objects[indexPath.row] stringByReplacingOccurrencesOfString:@"small" withString:@"source"]; NSURL *largeImageURL = [NSURL URLWithString:largeImageURLString]; DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil]; diff --git a/Examples/SDWebImage OSX Demo/ViewController.m b/Examples/SDWebImage OSX Demo/ViewController.m index a510b978..20477147 100644 --- a/Examples/SDWebImage OSX Demo/ViewController.m +++ b/Examples/SDWebImage OSX Demo/ViewController.m @@ -8,6 +8,7 @@ #import "ViewController.h" #import +#import @interface ViewController () @@ -24,6 +25,8 @@ - (void)viewDidLoad { [super viewDidLoad]; + [[SDImageCodersManager sharedManager] addCoder:[SDImageWebPCoder sharedCoder]]; + // For animated GIF rendering, set `animates` to YES or will only show the first frame self.imageView2.animates = YES; // `SDAnimatedImageRep` can be used for built-in `NSImageView` to support better GIF & APNG rendering as well. No need `SDAnimatedImageView` self.imageView3.animates = YES; diff --git a/Examples/SDWebImage TV Demo/ViewController.m b/Examples/SDWebImage TV Demo/ViewController.m index a2ad4904..6d001704 100644 --- a/Examples/SDWebImage TV Demo/ViewController.m +++ b/Examples/SDWebImage TV Demo/ViewController.m @@ -8,6 +8,7 @@ #import "ViewController.h" #import +#import @interface ViewController () @@ -24,6 +25,7 @@ - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. + [[SDImageCodersManager sharedManager] addCoder:[SDImageWebPCoder sharedCoder]]; [self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"]]; [self.imageView2 sd_setImageWithURL:[NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp"]]; diff --git a/Examples/SDWebImage Watch Demo Extension/InterfaceController.m b/Examples/SDWebImage Watch Demo Extension/InterfaceController.m index 521de388..08c3973e 100644 --- a/Examples/SDWebImage Watch Demo Extension/InterfaceController.m +++ b/Examples/SDWebImage Watch Demo Extension/InterfaceController.m @@ -8,6 +8,7 @@ #import "InterfaceController.h" #import +#import @interface InterfaceController() @@ -23,6 +24,7 @@ [super awakeWithContext:context]; // Configure interface objects here. + [[SDImageCodersManager sharedManager] addCoder:[SDImageWebPCoder sharedCoder]]; } - (void)willActivate { diff --git a/Examples/SDWebImage Watch Demo Extension/NotificationController.m b/Examples/SDWebImage Watch Demo Extension/NotificationController.m index 5482f38e..e92f6cd4 100644 --- a/Examples/SDWebImage Watch Demo Extension/NotificationController.m +++ b/Examples/SDWebImage Watch Demo Extension/NotificationController.m @@ -36,28 +36,6 @@ [super didDeactivate]; } -/* -- (void)didReceiveLocalNotification:(UILocalNotification *)localNotification withCompletion:(void (^)(WKUserNotificationInterfaceType))completionHandler { - // This method is called when a local notification needs to be presented. - // Implement it if you use a dynamic notification interface. - // Populate your dynamic notification interface as quickly as possible. - // - // After populating your dynamic notification interface call the completion block. - completionHandler(WKUserNotificationInterfaceTypeCustom); -} -*/ - -/* -- (void)didReceiveRemoteNotification:(NSDictionary *)remoteNotification withCompletion:(void (^)(WKUserNotificationInterfaceType))completionHandler { - // This method is called when a remote notification needs to be presented. - // Implement it if you use a dynamic notification interface. - // Populate your dynamic notification interface as quickly as possible. - // - // After populating your dynamic notification interface call the completion block. - completionHandler(WKUserNotificationInterfaceTypeCustom); -} -*/ - @end diff --git a/README.md b/README.md index 39659d2f..90800a4e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- +

@@ -32,7 +32,31 @@ This library provides an async image downloader with cache support. For convenie ## Supported Image Formats - Image formats supported by UIImage (JPEG, PNG, ...), including GIF -- WebP format, including animated WebP (use the `WebP` subspec) +- WebP format, including animated WebP (use the [SDWebImageWebPCoder](https://github.com/SDWebImage/SDWebImageWebPCoder) project) + +## Additional modules + +In order to keep SDWebImage focused and limited to the core features, but also allow extensibility and custom behaviors, during the 5.0 refactoring we focused on modularizing the library. +As such, we have moved/built new modules to [SDWebImage org](https://github.com/SDWebImage). + +#### Coders for additional image formats +- [SDWebImageWebPCoder](https://github.com/SDWebImage/SDWebImageWebPCoder) - coder for WebP image format. Based on [libwebp](https://chromium.googlesource.com/webm/libwebp) +- [SDWebImageHEIFCoder](https://github.com/SDWebImage/SDWebImageHEIFCoder) - coder to support HEIF image without Apple's `Image/IO framework` +- [SDWebImageAPNGCoder](https://github.com/SDWebImage/SDWebImageAPNGCoder) - coder for APNG format (animated PNG) +- [SDWebImageBPGCoder](https://github.com/SDWebImage/SDWebImageBPGCoder) - coder for BPG format + +#### Loaders +- [SDWebImagePhotosPlugin](https://github.com/SDWebImage/SDWebImagePhotosPlugin) - plugin to support loading images from Photos (using `Photos.framework`) + +#### Integration with 3rd party libraries +- [SDWebImageFLPlugin](https://github.com/SDWebImage/SDWebImageFLPlugin) - plugin to support [FLAnimatedImage](https://github.com/Flipboard/FLAnimatedImage) as the engine for animated GIFs +- [SDWebImageYYPlugin](https://github.com/SDWebImage/SDWebImageYYPlugin) - plugin to integrate [YYImage](https://github.com/ibireme/YYImage) & [YYCache](https://github.com/ibireme/YYCache) for image rendering & caching +- [SDWebImageProgressiveJPEGDemo](https://github.com/SDWebImage/SDWebImageProgressiveJPEGDemo) - demo project for using `SDWebImage` + [Concorde library](https://github.com/contentful-labs/Concorde) for Progressive JPEG decoding + +#### Make our lives easier +- [libwebp-Xcode](https://github.com/SDWebImage/libwebp-Xcode) - A wrapper for [libwebp](https://chromium.googlesource.com/webm/libwebp) + an Xcode project. + +You can use those directly, or create similar components of your own. ## Requirements @@ -56,8 +80,8 @@ This library provides an async image downloader with cache support. For convenie - Read the [Documentation @ CocoaDocs](http://cocoadocs.org/docsets/SDWebImage/) - Try the example by downloading the project from Github or even easier using CocoaPods try `pod try SDWebImage` - Read the [Installation Guide](https://github.com/rs/SDWebImage/wiki/Installation-Guide) -- Read the [SDWebImage 5.0 Migration Guide](Docs/SDWebImage-5.0-Migration-guide.md) to get an idea of the changes from 4.x to 5.x -- Read the [SDWebImage 4.0 Migration Guide](Docs/SDWebImage-4.0-Migration-guide.md) to get an idea of the changes from 3.x to 4.x +- Read the [SDWebImage 5.0 Migration Guide](https://raw.githubusercontent.com/rs/SDWebImage/5.x/Docs/SDWebImage-5.0-Migration-guide.md) to get an idea of the changes from 4.x to 5.x +- Read the [SDWebImage 4.0 Migration Guide](https://raw.githubusercontent.com/rs/SDWebImage/master/Docs/SDWebImage-4.0-Migration-guide.md) to get an idea of the changes from 3.x to 4.x - Read the [Common Problems](https://github.com/rs/SDWebImage/wiki/Common-Problems) to find the solution for common problems - Go to the [Wiki Page](https://github.com/rs/SDWebImage/wiki) for more information such as [Advanced Usage](https://github.com/rs/SDWebImage/wiki/Advanced-Usage) @@ -70,7 +94,7 @@ This library provides an async image downloader with cache support. For convenie - If you'd like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/sdwebimage). - If you **found a bug**, open an issue. - If you **have a feature request**, open an issue. -- If you **want to contribute**, submit a pull request. +- If you **want to contribute**, read the [Contributing Guide](https://raw.githubusercontent.com/rs/SDWebImage/master/.github/CONTRIBUTING.md) ## How To Use @@ -91,7 +115,7 @@ import SDWebImage imageView.sd_setImage(with: URL(string: "http://www.domain.com/path/to/image.jpg"), placeholderImage: UIImage(named: "placeholder.png")) ``` -- For details about how to use the library and clear examples, see [The detailed How to use](Docs/HowToUse.md) +- For details about how to use the library and clear examples, see [The detailed How to use](https://raw.githubusercontent.com/rs/SDWebImage/master/Docs/HowToUse.md) ## Animated Images (GIF) support @@ -126,11 +150,11 @@ use_frameworks! #### Subspecs -There are 3 subspecs available now: `Core`, `MapKit` and `WebP` (this means you can install only some of the SDWebImage modules. By default, you get just `Core`, so if you need `WebP`, you need to specify it). +There are 2 subspecs available now: `Core` and `MapKit` (this means you can install only some of the SDWebImage modules. By default, you get just `Core`, so if you need `MapKit`, you need to specify it). Podfile example: ``` -pod 'SDWebImage/WebP' +pod 'SDWebImage/MapKit' ``` ### Installation with Carthage (iOS 8+) @@ -145,7 +169,7 @@ github "rs/SDWebImage" ``` ### Installation by cloning the repository -- see [Manual install](Docs/ManualInstallation.md) +- see [Manual install](https://raw.githubusercontent.com/rs/SDWebImage/master/Docs/ManualInstallation.md) ### Import headers in your source files @@ -178,26 +202,26 @@ All source code is licensed under the [MIT License](https://raw.github.com/rs/SD #### High Level Diagram

- +

#### Overall Class Diagram

- +

#### Top Level API Diagram

- +

#### Main Sequence Diagram

- +

#### More detailed diagrams -- [Manager API Diagram](Docs/Diagrams/SDWebImageManagerClassDiagram.png) -- [Coders API Diagram](Docs/Diagrams/SDWebImageCodersClassDiagram.png) -- [Loader API Diagram](Docs/Diagrams/SDWebImageLoaderClassDiagram.png) -- [Cache API Diagram](Docs/Diagrams/SDWebImageCacheClassDiagram.png) \ No newline at end of file +- [Manager API Diagram](https://raw.githubusercontent.com/rs/SDWebImage/5.x/Docs/Diagrams/SDWebImageManagerClassDiagram.png) +- [Coders API Diagram](https://raw.githubusercontent.com/rs/SDWebImage/5.x/Docs/Diagrams/SDWebImageCodersClassDiagram.png) +- [Loader API Diagram](https://raw.githubusercontent.com/rs/SDWebImage/5.x/Docs/Diagrams/SDWebImageLoaderClassDiagram.png) +- [Cache API Diagram](https://raw.githubusercontent.com/rs/SDWebImage/5.x/Docs/Diagrams/SDWebImageCacheClassDiagram.png) diff --git a/SDWebImage.podspec b/SDWebImage.podspec index 5dcb72b4..860e9fdc 100644 --- a/SDWebImage.podspec +++ b/SDWebImage.podspec @@ -29,7 +29,7 @@ Pod::Spec.new do |s| s.subspec 'Core' do |core| core.source_files = 'SDWebImage/*.{h,m}', 'WebImage/SDWebImage.h' - core.exclude_files = 'SDWebImage/MapKit/*.{h,m}', 'SDWebImage/WebP/*.{h,m}' + core.exclude_files = 'SDWebImage/MapKit/*.{h,m}' end s.subspec 'MapKit' do |mk| @@ -40,18 +40,4 @@ Pod::Spec.new do |s| mk.framework = 'MapKit' mk.dependency 'SDWebImage/Core' end - - s.subspec 'WebP' do |webp| - webp.source_files = 'SDWebImage/WebP/*.{h,m}' - webp.xcconfig = { - 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SD_WEBP=1', - 'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/libwebp/src' - } - webp.watchos.xcconfig = { - 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SD_WEBP=1 WEBP_USE_INTRINSICS=1', - 'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/libwebp/src' - } - webp.dependency 'SDWebImage/Core' - webp.dependency 'libwebp', '~> 0.5' - end end diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 06882856..0e1a5c28 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -128,216 +128,6 @@ 3237F9EA20161AE000A88143 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; 3237F9EB20161AE000A88143 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; 3237F9EC20161AE000A88143 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; - 323F8B3E1F38EF770092B609 /* alpha_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B131F38EF770092B609 /* alpha_enc.c */; }; - 323F8B3F1F38EF770092B609 /* alpha_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B131F38EF770092B609 /* alpha_enc.c */; }; - 323F8B401F38EF770092B609 /* alpha_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B131F38EF770092B609 /* alpha_enc.c */; }; - 323F8B411F38EF770092B609 /* alpha_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B131F38EF770092B609 /* alpha_enc.c */; }; - 323F8B421F38EF770092B609 /* alpha_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B131F38EF770092B609 /* alpha_enc.c */; }; - 323F8B431F38EF770092B609 /* alpha_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B131F38EF770092B609 /* alpha_enc.c */; }; - 323F8B441F38EF770092B609 /* analysis_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B141F38EF770092B609 /* analysis_enc.c */; }; - 323F8B451F38EF770092B609 /* analysis_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B141F38EF770092B609 /* analysis_enc.c */; }; - 323F8B461F38EF770092B609 /* analysis_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B141F38EF770092B609 /* analysis_enc.c */; }; - 323F8B471F38EF770092B609 /* analysis_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B141F38EF770092B609 /* analysis_enc.c */; }; - 323F8B481F38EF770092B609 /* analysis_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B141F38EF770092B609 /* analysis_enc.c */; }; - 323F8B491F38EF770092B609 /* analysis_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B141F38EF770092B609 /* analysis_enc.c */; }; - 323F8B4A1F38EF770092B609 /* backward_references_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B151F38EF770092B609 /* backward_references_enc.c */; }; - 323F8B4B1F38EF770092B609 /* backward_references_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B151F38EF770092B609 /* backward_references_enc.c */; }; - 323F8B4C1F38EF770092B609 /* backward_references_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B151F38EF770092B609 /* backward_references_enc.c */; }; - 323F8B4D1F38EF770092B609 /* backward_references_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B151F38EF770092B609 /* backward_references_enc.c */; }; - 323F8B4E1F38EF770092B609 /* backward_references_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B151F38EF770092B609 /* backward_references_enc.c */; }; - 323F8B4F1F38EF770092B609 /* backward_references_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B151F38EF770092B609 /* backward_references_enc.c */; }; - 323F8B501F38EF770092B609 /* backward_references_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B161F38EF770092B609 /* backward_references_enc.h */; }; - 323F8B511F38EF770092B609 /* backward_references_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B161F38EF770092B609 /* backward_references_enc.h */; }; - 323F8B521F38EF770092B609 /* backward_references_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B161F38EF770092B609 /* backward_references_enc.h */; }; - 323F8B531F38EF770092B609 /* backward_references_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B161F38EF770092B609 /* backward_references_enc.h */; }; - 323F8B541F38EF770092B609 /* backward_references_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B161F38EF770092B609 /* backward_references_enc.h */; }; - 323F8B551F38EF770092B609 /* backward_references_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B161F38EF770092B609 /* backward_references_enc.h */; }; - 323F8B561F38EF770092B609 /* config_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B171F38EF770092B609 /* config_enc.c */; }; - 323F8B571F38EF770092B609 /* config_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B171F38EF770092B609 /* config_enc.c */; }; - 323F8B581F38EF770092B609 /* config_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B171F38EF770092B609 /* config_enc.c */; }; - 323F8B591F38EF770092B609 /* config_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B171F38EF770092B609 /* config_enc.c */; }; - 323F8B5A1F38EF770092B609 /* config_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B171F38EF770092B609 /* config_enc.c */; }; - 323F8B5B1F38EF770092B609 /* config_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B171F38EF770092B609 /* config_enc.c */; }; - 323F8B5C1F38EF770092B609 /* cost_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B181F38EF770092B609 /* cost_enc.c */; }; - 323F8B5D1F38EF770092B609 /* cost_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B181F38EF770092B609 /* cost_enc.c */; }; - 323F8B5E1F38EF770092B609 /* cost_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B181F38EF770092B609 /* cost_enc.c */; }; - 323F8B5F1F38EF770092B609 /* cost_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B181F38EF770092B609 /* cost_enc.c */; }; - 323F8B601F38EF770092B609 /* cost_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B181F38EF770092B609 /* cost_enc.c */; }; - 323F8B611F38EF770092B609 /* cost_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B181F38EF770092B609 /* cost_enc.c */; }; - 323F8B621F38EF770092B609 /* cost_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B191F38EF770092B609 /* cost_enc.h */; }; - 323F8B631F38EF770092B609 /* cost_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B191F38EF770092B609 /* cost_enc.h */; }; - 323F8B641F38EF770092B609 /* cost_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B191F38EF770092B609 /* cost_enc.h */; }; - 323F8B651F38EF770092B609 /* cost_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B191F38EF770092B609 /* cost_enc.h */; }; - 323F8B661F38EF770092B609 /* cost_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B191F38EF770092B609 /* cost_enc.h */; }; - 323F8B671F38EF770092B609 /* cost_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B191F38EF770092B609 /* cost_enc.h */; }; - 323F8B681F38EF770092B609 /* delta_palettization_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1A1F38EF770092B609 /* delta_palettization_enc.c */; }; - 323F8B691F38EF770092B609 /* delta_palettization_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1A1F38EF770092B609 /* delta_palettization_enc.c */; }; - 323F8B6A1F38EF770092B609 /* delta_palettization_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1A1F38EF770092B609 /* delta_palettization_enc.c */; }; - 323F8B6B1F38EF770092B609 /* delta_palettization_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1A1F38EF770092B609 /* delta_palettization_enc.c */; }; - 323F8B6C1F38EF770092B609 /* delta_palettization_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1A1F38EF770092B609 /* delta_palettization_enc.c */; }; - 323F8B6D1F38EF770092B609 /* delta_palettization_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1A1F38EF770092B609 /* delta_palettization_enc.c */; }; - 323F8B6E1F38EF770092B609 /* delta_palettization_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B1B1F38EF770092B609 /* delta_palettization_enc.h */; }; - 323F8B6F1F38EF770092B609 /* delta_palettization_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B1B1F38EF770092B609 /* delta_palettization_enc.h */; }; - 323F8B701F38EF770092B609 /* delta_palettization_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B1B1F38EF770092B609 /* delta_palettization_enc.h */; }; - 323F8B711F38EF770092B609 /* delta_palettization_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B1B1F38EF770092B609 /* delta_palettization_enc.h */; }; - 323F8B721F38EF770092B609 /* delta_palettization_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B1B1F38EF770092B609 /* delta_palettization_enc.h */; }; - 323F8B731F38EF770092B609 /* delta_palettization_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B1B1F38EF770092B609 /* delta_palettization_enc.h */; }; - 323F8B741F38EF770092B609 /* filter_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1C1F38EF770092B609 /* filter_enc.c */; }; - 323F8B751F38EF770092B609 /* filter_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1C1F38EF770092B609 /* filter_enc.c */; }; - 323F8B761F38EF770092B609 /* filter_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1C1F38EF770092B609 /* filter_enc.c */; }; - 323F8B771F38EF770092B609 /* filter_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1C1F38EF770092B609 /* filter_enc.c */; }; - 323F8B781F38EF770092B609 /* filter_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1C1F38EF770092B609 /* filter_enc.c */; }; - 323F8B791F38EF770092B609 /* filter_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1C1F38EF770092B609 /* filter_enc.c */; }; - 323F8B7A1F38EF770092B609 /* frame_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1D1F38EF770092B609 /* frame_enc.c */; }; - 323F8B7B1F38EF770092B609 /* frame_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1D1F38EF770092B609 /* frame_enc.c */; }; - 323F8B7C1F38EF770092B609 /* frame_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1D1F38EF770092B609 /* frame_enc.c */; }; - 323F8B7D1F38EF770092B609 /* frame_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1D1F38EF770092B609 /* frame_enc.c */; }; - 323F8B7E1F38EF770092B609 /* frame_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1D1F38EF770092B609 /* frame_enc.c */; }; - 323F8B7F1F38EF770092B609 /* frame_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1D1F38EF770092B609 /* frame_enc.c */; }; - 323F8B801F38EF770092B609 /* histogram_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1E1F38EF770092B609 /* histogram_enc.c */; }; - 323F8B811F38EF770092B609 /* histogram_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1E1F38EF770092B609 /* histogram_enc.c */; }; - 323F8B821F38EF770092B609 /* histogram_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1E1F38EF770092B609 /* histogram_enc.c */; }; - 323F8B831F38EF770092B609 /* histogram_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1E1F38EF770092B609 /* histogram_enc.c */; }; - 323F8B841F38EF770092B609 /* histogram_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1E1F38EF770092B609 /* histogram_enc.c */; }; - 323F8B851F38EF770092B609 /* histogram_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B1E1F38EF770092B609 /* histogram_enc.c */; }; - 323F8B861F38EF770092B609 /* histogram_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B1F1F38EF770092B609 /* histogram_enc.h */; }; - 323F8B871F38EF770092B609 /* histogram_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B1F1F38EF770092B609 /* histogram_enc.h */; }; - 323F8B881F38EF770092B609 /* histogram_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B1F1F38EF770092B609 /* histogram_enc.h */; }; - 323F8B891F38EF770092B609 /* histogram_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B1F1F38EF770092B609 /* histogram_enc.h */; }; - 323F8B8A1F38EF770092B609 /* histogram_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B1F1F38EF770092B609 /* histogram_enc.h */; }; - 323F8B8B1F38EF770092B609 /* histogram_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B1F1F38EF770092B609 /* histogram_enc.h */; }; - 323F8B8C1F38EF770092B609 /* iterator_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B201F38EF770092B609 /* iterator_enc.c */; }; - 323F8B8D1F38EF770092B609 /* iterator_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B201F38EF770092B609 /* iterator_enc.c */; }; - 323F8B8E1F38EF770092B609 /* iterator_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B201F38EF770092B609 /* iterator_enc.c */; }; - 323F8B8F1F38EF770092B609 /* iterator_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B201F38EF770092B609 /* iterator_enc.c */; }; - 323F8B901F38EF770092B609 /* iterator_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B201F38EF770092B609 /* iterator_enc.c */; }; - 323F8B911F38EF770092B609 /* iterator_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B201F38EF770092B609 /* iterator_enc.c */; }; - 323F8B961F38EF770092B609 /* near_lossless_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B221F38EF770092B609 /* near_lossless_enc.c */; }; - 323F8B971F38EF770092B609 /* near_lossless_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B221F38EF770092B609 /* near_lossless_enc.c */; }; - 323F8B981F38EF770092B609 /* near_lossless_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B221F38EF770092B609 /* near_lossless_enc.c */; }; - 323F8B991F38EF770092B609 /* near_lossless_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B221F38EF770092B609 /* near_lossless_enc.c */; }; - 323F8B9A1F38EF770092B609 /* near_lossless_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B221F38EF770092B609 /* near_lossless_enc.c */; }; - 323F8B9B1F38EF770092B609 /* near_lossless_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B221F38EF770092B609 /* near_lossless_enc.c */; }; - 323F8B9C1F38EF770092B609 /* picture_csp_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B231F38EF770092B609 /* picture_csp_enc.c */; }; - 323F8B9D1F38EF770092B609 /* picture_csp_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B231F38EF770092B609 /* picture_csp_enc.c */; }; - 323F8B9E1F38EF770092B609 /* picture_csp_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B231F38EF770092B609 /* picture_csp_enc.c */; }; - 323F8B9F1F38EF770092B609 /* picture_csp_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B231F38EF770092B609 /* picture_csp_enc.c */; }; - 323F8BA01F38EF770092B609 /* picture_csp_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B231F38EF770092B609 /* picture_csp_enc.c */; }; - 323F8BA11F38EF770092B609 /* picture_csp_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B231F38EF770092B609 /* picture_csp_enc.c */; }; - 323F8BA21F38EF770092B609 /* picture_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B241F38EF770092B609 /* picture_enc.c */; }; - 323F8BA31F38EF770092B609 /* picture_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B241F38EF770092B609 /* picture_enc.c */; }; - 323F8BA41F38EF770092B609 /* picture_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B241F38EF770092B609 /* picture_enc.c */; }; - 323F8BA51F38EF770092B609 /* picture_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B241F38EF770092B609 /* picture_enc.c */; }; - 323F8BA61F38EF770092B609 /* picture_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B241F38EF770092B609 /* picture_enc.c */; }; - 323F8BA71F38EF770092B609 /* picture_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B241F38EF770092B609 /* picture_enc.c */; }; - 323F8BA81F38EF770092B609 /* picture_psnr_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B251F38EF770092B609 /* picture_psnr_enc.c */; }; - 323F8BA91F38EF770092B609 /* picture_psnr_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B251F38EF770092B609 /* picture_psnr_enc.c */; }; - 323F8BAA1F38EF770092B609 /* picture_psnr_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B251F38EF770092B609 /* picture_psnr_enc.c */; }; - 323F8BAB1F38EF770092B609 /* picture_psnr_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B251F38EF770092B609 /* picture_psnr_enc.c */; }; - 323F8BAC1F38EF770092B609 /* picture_psnr_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B251F38EF770092B609 /* picture_psnr_enc.c */; }; - 323F8BAD1F38EF770092B609 /* picture_psnr_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B251F38EF770092B609 /* picture_psnr_enc.c */; }; - 323F8BAE1F38EF770092B609 /* picture_rescale_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B261F38EF770092B609 /* picture_rescale_enc.c */; }; - 323F8BAF1F38EF770092B609 /* picture_rescale_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B261F38EF770092B609 /* picture_rescale_enc.c */; }; - 323F8BB01F38EF770092B609 /* picture_rescale_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B261F38EF770092B609 /* picture_rescale_enc.c */; }; - 323F8BB11F38EF770092B609 /* picture_rescale_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B261F38EF770092B609 /* picture_rescale_enc.c */; }; - 323F8BB21F38EF770092B609 /* picture_rescale_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B261F38EF770092B609 /* picture_rescale_enc.c */; }; - 323F8BB31F38EF770092B609 /* picture_rescale_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B261F38EF770092B609 /* picture_rescale_enc.c */; }; - 323F8BB41F38EF770092B609 /* picture_tools_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B271F38EF770092B609 /* picture_tools_enc.c */; }; - 323F8BB51F38EF770092B609 /* picture_tools_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B271F38EF770092B609 /* picture_tools_enc.c */; }; - 323F8BB61F38EF770092B609 /* picture_tools_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B271F38EF770092B609 /* picture_tools_enc.c */; }; - 323F8BB71F38EF770092B609 /* picture_tools_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B271F38EF770092B609 /* picture_tools_enc.c */; }; - 323F8BB81F38EF770092B609 /* picture_tools_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B271F38EF770092B609 /* picture_tools_enc.c */; }; - 323F8BB91F38EF770092B609 /* picture_tools_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B271F38EF770092B609 /* picture_tools_enc.c */; }; - 323F8BBA1F38EF770092B609 /* predictor_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B281F38EF770092B609 /* predictor_enc.c */; }; - 323F8BBB1F38EF770092B609 /* predictor_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B281F38EF770092B609 /* predictor_enc.c */; }; - 323F8BBC1F38EF770092B609 /* predictor_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B281F38EF770092B609 /* predictor_enc.c */; }; - 323F8BBD1F38EF770092B609 /* predictor_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B281F38EF770092B609 /* predictor_enc.c */; }; - 323F8BBE1F38EF770092B609 /* predictor_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B281F38EF770092B609 /* predictor_enc.c */; }; - 323F8BBF1F38EF770092B609 /* predictor_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B281F38EF770092B609 /* predictor_enc.c */; }; - 323F8BC01F38EF770092B609 /* quant_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B291F38EF770092B609 /* quant_enc.c */; }; - 323F8BC11F38EF770092B609 /* quant_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B291F38EF770092B609 /* quant_enc.c */; }; - 323F8BC21F38EF770092B609 /* quant_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B291F38EF770092B609 /* quant_enc.c */; }; - 323F8BC31F38EF770092B609 /* quant_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B291F38EF770092B609 /* quant_enc.c */; }; - 323F8BC41F38EF770092B609 /* quant_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B291F38EF770092B609 /* quant_enc.c */; }; - 323F8BC51F38EF770092B609 /* quant_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B291F38EF770092B609 /* quant_enc.c */; }; - 323F8BC61F38EF770092B609 /* syntax_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2A1F38EF770092B609 /* syntax_enc.c */; }; - 323F8BC71F38EF770092B609 /* syntax_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2A1F38EF770092B609 /* syntax_enc.c */; }; - 323F8BC81F38EF770092B609 /* syntax_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2A1F38EF770092B609 /* syntax_enc.c */; }; - 323F8BC91F38EF770092B609 /* syntax_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2A1F38EF770092B609 /* syntax_enc.c */; }; - 323F8BCA1F38EF770092B609 /* syntax_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2A1F38EF770092B609 /* syntax_enc.c */; }; - 323F8BCB1F38EF770092B609 /* syntax_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2A1F38EF770092B609 /* syntax_enc.c */; }; - 323F8BCC1F38EF770092B609 /* token_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2B1F38EF770092B609 /* token_enc.c */; }; - 323F8BCD1F38EF770092B609 /* token_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2B1F38EF770092B609 /* token_enc.c */; }; - 323F8BCE1F38EF770092B609 /* token_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2B1F38EF770092B609 /* token_enc.c */; }; - 323F8BCF1F38EF770092B609 /* token_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2B1F38EF770092B609 /* token_enc.c */; }; - 323F8BD01F38EF770092B609 /* token_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2B1F38EF770092B609 /* token_enc.c */; }; - 323F8BD11F38EF770092B609 /* token_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2B1F38EF770092B609 /* token_enc.c */; }; - 323F8BD21F38EF770092B609 /* tree_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2C1F38EF770092B609 /* tree_enc.c */; }; - 323F8BD31F38EF770092B609 /* tree_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2C1F38EF770092B609 /* tree_enc.c */; }; - 323F8BD41F38EF770092B609 /* tree_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2C1F38EF770092B609 /* tree_enc.c */; }; - 323F8BD51F38EF770092B609 /* tree_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2C1F38EF770092B609 /* tree_enc.c */; }; - 323F8BD61F38EF770092B609 /* tree_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2C1F38EF770092B609 /* tree_enc.c */; }; - 323F8BD71F38EF770092B609 /* tree_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2C1F38EF770092B609 /* tree_enc.c */; }; - 323F8BD81F38EF770092B609 /* vp8i_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B2D1F38EF770092B609 /* vp8i_enc.h */; }; - 323F8BD91F38EF770092B609 /* vp8i_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B2D1F38EF770092B609 /* vp8i_enc.h */; }; - 323F8BDA1F38EF770092B609 /* vp8i_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B2D1F38EF770092B609 /* vp8i_enc.h */; }; - 323F8BDB1F38EF770092B609 /* vp8i_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B2D1F38EF770092B609 /* vp8i_enc.h */; }; - 323F8BDC1F38EF770092B609 /* vp8i_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B2D1F38EF770092B609 /* vp8i_enc.h */; }; - 323F8BDD1F38EF770092B609 /* vp8i_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B2D1F38EF770092B609 /* vp8i_enc.h */; }; - 323F8BDE1F38EF770092B609 /* vp8l_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2E1F38EF770092B609 /* vp8l_enc.c */; }; - 323F8BDF1F38EF770092B609 /* vp8l_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2E1F38EF770092B609 /* vp8l_enc.c */; }; - 323F8BE01F38EF770092B609 /* vp8l_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2E1F38EF770092B609 /* vp8l_enc.c */; }; - 323F8BE11F38EF770092B609 /* vp8l_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2E1F38EF770092B609 /* vp8l_enc.c */; }; - 323F8BE21F38EF770092B609 /* vp8l_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2E1F38EF770092B609 /* vp8l_enc.c */; }; - 323F8BE31F38EF770092B609 /* vp8l_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B2E1F38EF770092B609 /* vp8l_enc.c */; }; - 323F8BE41F38EF770092B609 /* vp8li_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B2F1F38EF770092B609 /* vp8li_enc.h */; }; - 323F8BE51F38EF770092B609 /* vp8li_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B2F1F38EF770092B609 /* vp8li_enc.h */; }; - 323F8BE61F38EF770092B609 /* vp8li_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B2F1F38EF770092B609 /* vp8li_enc.h */; }; - 323F8BE71F38EF770092B609 /* vp8li_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B2F1F38EF770092B609 /* vp8li_enc.h */; }; - 323F8BE81F38EF770092B609 /* vp8li_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B2F1F38EF770092B609 /* vp8li_enc.h */; }; - 323F8BE91F38EF770092B609 /* vp8li_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B2F1F38EF770092B609 /* vp8li_enc.h */; }; - 323F8BEA1F38EF770092B609 /* webp_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B301F38EF770092B609 /* webp_enc.c */; }; - 323F8BEB1F38EF770092B609 /* webp_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B301F38EF770092B609 /* webp_enc.c */; }; - 323F8BEC1F38EF770092B609 /* webp_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B301F38EF770092B609 /* webp_enc.c */; }; - 323F8BED1F38EF770092B609 /* webp_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B301F38EF770092B609 /* webp_enc.c */; }; - 323F8BEE1F38EF770092B609 /* webp_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B301F38EF770092B609 /* webp_enc.c */; }; - 323F8BEF1F38EF770092B609 /* webp_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B301F38EF770092B609 /* webp_enc.c */; }; - 323F8BF01F38EF770092B609 /* anim_encode.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B321F38EF770092B609 /* anim_encode.c */; }; - 323F8BF11F38EF770092B609 /* anim_encode.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B321F38EF770092B609 /* anim_encode.c */; }; - 323F8BF21F38EF770092B609 /* anim_encode.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B321F38EF770092B609 /* anim_encode.c */; }; - 323F8BF31F38EF770092B609 /* anim_encode.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B321F38EF770092B609 /* anim_encode.c */; }; - 323F8BF41F38EF770092B609 /* anim_encode.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B321F38EF770092B609 /* anim_encode.c */; }; - 323F8BF51F38EF770092B609 /* anim_encode.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B321F38EF770092B609 /* anim_encode.c */; }; - 323F8BF61F38EF770092B609 /* animi.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B331F38EF770092B609 /* animi.h */; }; - 323F8BF71F38EF770092B609 /* animi.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B331F38EF770092B609 /* animi.h */; }; - 323F8BF81F38EF770092B609 /* animi.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B331F38EF770092B609 /* animi.h */; }; - 323F8BF91F38EF770092B609 /* animi.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B331F38EF770092B609 /* animi.h */; }; - 323F8BFA1F38EF770092B609 /* animi.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B331F38EF770092B609 /* animi.h */; }; - 323F8BFB1F38EF770092B609 /* animi.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B331F38EF770092B609 /* animi.h */; }; - 323F8C081F38EF770092B609 /* muxedit.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3A1F38EF770092B609 /* muxedit.c */; }; - 323F8C091F38EF770092B609 /* muxedit.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3A1F38EF770092B609 /* muxedit.c */; }; - 323F8C0A1F38EF770092B609 /* muxedit.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3A1F38EF770092B609 /* muxedit.c */; }; - 323F8C0B1F38EF770092B609 /* muxedit.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3A1F38EF770092B609 /* muxedit.c */; }; - 323F8C0C1F38EF770092B609 /* muxedit.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3A1F38EF770092B609 /* muxedit.c */; }; - 323F8C0D1F38EF770092B609 /* muxedit.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3A1F38EF770092B609 /* muxedit.c */; }; - 323F8C0E1F38EF770092B609 /* muxi.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B3B1F38EF770092B609 /* muxi.h */; }; - 323F8C0F1F38EF770092B609 /* muxi.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B3B1F38EF770092B609 /* muxi.h */; }; - 323F8C101F38EF770092B609 /* muxi.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B3B1F38EF770092B609 /* muxi.h */; }; - 323F8C111F38EF770092B609 /* muxi.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B3B1F38EF770092B609 /* muxi.h */; }; - 323F8C121F38EF770092B609 /* muxi.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B3B1F38EF770092B609 /* muxi.h */; }; - 323F8C131F38EF770092B609 /* muxi.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8B3B1F38EF770092B609 /* muxi.h */; }; - 323F8C141F38EF770092B609 /* muxinternal.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3C1F38EF770092B609 /* muxinternal.c */; }; - 323F8C151F38EF770092B609 /* muxinternal.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3C1F38EF770092B609 /* muxinternal.c */; }; - 323F8C161F38EF770092B609 /* muxinternal.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3C1F38EF770092B609 /* muxinternal.c */; }; - 323F8C171F38EF770092B609 /* muxinternal.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3C1F38EF770092B609 /* muxinternal.c */; }; - 323F8C181F38EF770092B609 /* muxinternal.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3C1F38EF770092B609 /* muxinternal.c */; }; - 323F8C191F38EF770092B609 /* muxinternal.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3C1F38EF770092B609 /* muxinternal.c */; }; - 323F8C1A1F38EF770092B609 /* muxread.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3D1F38EF770092B609 /* muxread.c */; }; - 323F8C1B1F38EF770092B609 /* muxread.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3D1F38EF770092B609 /* muxread.c */; }; - 323F8C1C1F38EF770092B609 /* muxread.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3D1F38EF770092B609 /* muxread.c */; }; - 323F8C1D1F38EF770092B609 /* muxread.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3D1F38EF770092B609 /* muxread.c */; }; - 323F8C1E1F38EF770092B609 /* muxread.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3D1F38EF770092B609 /* muxread.c */; }; - 323F8C1F1F38EF770092B609 /* muxread.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B3D1F38EF770092B609 /* muxread.c */; }; 3248475D201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; 3248475E201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; 3248475F201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; @@ -591,30 +381,6 @@ 32FDE8812088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32FDE8822088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32FDE8832088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE88920888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; - 32FDE88A20888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; - 32FDE88B20888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; - 32FDE88C20888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; - 32FDE88D20888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; - 32FDE88E20888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; - 32FDE88F20888726008D7530 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89020888726008D7530 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89120888726008D7530 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89220888726008D7530 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89320888726008D7530 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89420888726008D7530 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89520888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89620888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89720888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89820888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89920888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89A20888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89B20888726008D7530 /* SDImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDImageWebPCoder.m */; }; - 32FDE89C20888726008D7530 /* SDImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDImageWebPCoder.m */; }; - 32FDE89D20888726008D7530 /* SDImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDImageWebPCoder.m */; }; - 32FDE89E20888726008D7530 /* SDImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDImageWebPCoder.m */; }; - 32FDE89F20888726008D7530 /* SDImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDImageWebPCoder.m */; }; - 32FDE8A020888726008D7530 /* SDImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDImageWebPCoder.m */; }; 32FDE8A220888789008D7530 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32FDE8A320888789008D7530 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D1231D0E0E3B004B36C9 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D86148C56230056699D /* SDImageCache.m */; }; @@ -633,15 +399,9 @@ 4314D15E1D0E0E3B004B36C9 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53FB894814D35E9E0020B787 /* UIKit.framework */; }; 4314D15F1D0E0E3B004B36C9 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53922D72148C55820056699D /* Foundation.framework */; }; 4314D1601D0E0E3B004B36C9 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53FB893F14D35D1A0020B787 /* CoreGraphics.framework */; }; - 4314D1621D0E0E3B004B36C9 /* mux_types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC91998E60B007367ED /* mux_types.h */; }; - 4314D1631D0E0E3B004B36C9 /* demux.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC51998E60B007367ED /* demux.h */; }; - 4314D16B1D0E0E3B004B36C9 /* encode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC61998E60B007367ED /* encode.h */; }; 4314D16D1D0E0E3B004B36C9 /* SDImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D85148C56230056699D /* SDImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D16F1D0E0E3B004B36C9 /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D1701D0E0E3B004B36C9 /* mux.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC81998E60B007367ED /* mux.h */; }; 4314D1721D0E0E3B004B36C9 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D88148C56230056699D /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D1741D0E0E3B004B36C9 /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CCA1998E60B007367ED /* types.h */; }; - 4314D1761D0E0E3B004B36C9 /* decode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC41998E60B007367ED /* decode.h */; }; 4314D1781D0E0E3B004B36C9 /* SDWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8B148C56230056699D /* SDWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D1791D0E0E3B004B36C9 /* SDWebImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8E148C56230056699D /* SDWebImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D17D1D0E0E3B004B36C9 /* SDWebImagePrefetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D91148C56230056699D /* SDWebImagePrefetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -650,31 +410,9 @@ 4314D1841D0E0E3B004B36C9 /* SDWebImageOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 530E49E71646388E002868E7 /* SDWebImageOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D1851D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 530E49E316460AE2002868E7 /* SDWebImageDownloaderOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D1861D0E0E3B004B36C9 /* UIImageView+HighlightedWebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = ABBE71A518C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D1881D0E0E3B004B36C9 /* format_constants.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC71998E60B007367ED /* format_constants.h */; }; 4314D18F1D0E0E3B004B36C9 /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D1901D0E0E3B004B36C9 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D1921D0E0E3B004B36C9 /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431738BD1CDFC2660008FEB9 /* decode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC41998E60B007367ED /* decode.h */; }; - 431738BE1CDFC2660008FEB9 /* demux.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC51998E60B007367ED /* demux.h */; }; - 431738BF1CDFC2660008FEB9 /* encode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC61998E60B007367ED /* encode.h */; }; - 431738C01CDFC2660008FEB9 /* format_constants.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC71998E60B007367ED /* format_constants.h */; }; - 431738C11CDFC2660008FEB9 /* mux.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC81998E60B007367ED /* mux.h */; }; - 431738C21CDFC2660008FEB9 /* mux_types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC91998E60B007367ED /* mux_types.h */; }; - 431738C31CDFC2660008FEB9 /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CCA1998E60B007367ED /* types.h */; }; - 4317394E1CDFC8B70008FEB9 /* decode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC41998E60B007367ED /* decode.h */; }; - 4317394F1CDFC8B70008FEB9 /* demux.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC51998E60B007367ED /* demux.h */; }; - 431739501CDFC8B70008FEB9 /* encode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC61998E60B007367ED /* encode.h */; }; - 431739511CDFC8B70008FEB9 /* format_constants.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC71998E60B007367ED /* format_constants.h */; }; - 431739521CDFC8B70008FEB9 /* mux.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC81998E60B007367ED /* mux.h */; }; - 431739531CDFC8B70008FEB9 /* mux_types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC91998E60B007367ED /* mux_types.h */; }; - 431739541CDFC8B70008FEB9 /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CCA1998E60B007367ED /* types.h */; }; - 431739551CDFC8B70008FEB9 /* decode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC41998E60B007367ED /* decode.h */; }; - 431739561CDFC8B70008FEB9 /* demux.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC51998E60B007367ED /* demux.h */; }; - 431739571CDFC8B70008FEB9 /* encode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC61998E60B007367ED /* encode.h */; }; - 431739581CDFC8B70008FEB9 /* format_constants.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC71998E60B007367ED /* format_constants.h */; }; - 431739591CDFC8B70008FEB9 /* mux.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC81998E60B007367ED /* mux.h */; }; - 4317395A1CDFC8B70008FEB9 /* mux_types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC91998E60B007367ED /* mux_types.h */; }; - 4317395B1CDFC8B70008FEB9 /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CCA1998E60B007367ED /* types.h */; }; 431BB68C1D06D2C1006A3455 /* SDWebImageDownloaderOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 530E49E416460AE2002868E7 /* SDWebImageDownloaderOperation.m */; }; 431BB68E1D06D2C1006A3455 /* SDWebImagePrefetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D92148C56230056699D /* SDWebImagePrefetcher.m */; }; 431BB6921D06D2C1006A3455 /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */; }; @@ -728,37 +466,23 @@ 4397D2AB1D0DDD8C00BB2784 /* UIView+WebCacheOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AB615302192DA24600A2D8E9 /* UIView+WebCacheOperation.m */; }; 4397D2AE1D0DDD8C00BB2784 /* UIImageView+HighlightedWebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */; }; 4397D2B01D0DDD8C00BB2784 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D86148C56230056699D /* SDImageCache.m */; }; - 4397D2BA1D0DDD8C00BB2784 /* demux.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC51998E60B007367ED /* demux.h */; }; - 4397D2BD1D0DDD8C00BB2784 /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CCA1998E60B007367ED /* types.h */; }; 4397D2C01D0DDD8C00BB2784 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2C11D0DDD8C00BB2784 /* format_constants.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC71998E60B007367ED /* format_constants.h */; }; 4397D2C31D0DDD8C00BB2784 /* SDWebImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8E148C56230056699D /* SDWebImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2C41D0DDD8C00BB2784 /* SDImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D85148C56230056699D /* SDImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2C51D0DDD8C00BB2784 /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D95148C56230056699D /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2C81D0DDD8C00BB2784 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D88148C56230056699D /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2CB1D0DDD8C00BB2784 /* UIImageView+HighlightedWebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = ABBE71A518C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2CC1D0DDD8C00BB2784 /* mux.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC81998E60B007367ED /* mux.h */; }; 4397D2D01D0DDD8C00BB2784 /* SDWebImageDownloaderOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 530E49E316460AE2002868E7 /* SDWebImageDownloaderOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2D11D0DDD8C00BB2784 /* decode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC41998E60B007367ED /* decode.h */; }; 4397D2D81D0DDD8C00BB2784 /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D93148C56230056699D /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2D91D0DDD8C00BB2784 /* SDWebImagePrefetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D91148C56230056699D /* SDWebImagePrefetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2DA1D0DDD8C00BB2784 /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2DB1D0DDD8C00BB2784 /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2DC1D0DDD8C00BB2784 /* SDWebImageOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 530E49E71646388E002868E7 /* SDWebImageOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2E11D0DDD8C00BB2784 /* SDWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8B148C56230056699D /* SDWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2E61D0DDD8C00BB2784 /* encode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC61998E60B007367ED /* encode.h */; }; 4397D2EA1D0DDD8C00BB2784 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2EB1D0DDD8C00BB2784 /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2ED1D0DDD8C00BB2784 /* mux_types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC91998E60B007367ED /* mux_types.h */; }; 4397D2F61D0DE2DF00BB2784 /* NSImage+Compatibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 4397D2F41D0DE2DF00BB2784 /* NSImage+Compatibility.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2F71D0DE2DF00BB2784 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; - 43A62A1B1D0E0A800089D7DD /* decode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC41998E60B007367ED /* decode.h */; }; - 43A62A1C1D0E0A800089D7DD /* demux.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC51998E60B007367ED /* demux.h */; }; - 43A62A1D1D0E0A800089D7DD /* encode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC61998E60B007367ED /* encode.h */; }; - 43A62A1E1D0E0A800089D7DD /* format_constants.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC71998E60B007367ED /* format_constants.h */; }; - 43A62A1F1D0E0A800089D7DD /* mux.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC81998E60B007367ED /* mux.h */; }; - 43A62A201D0E0A800089D7DD /* mux_types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC91998E60B007367ED /* mux_types.h */; }; - 43A62A211D0E0A800089D7DD /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CCA1998E60B007367ED /* types.h */; }; 43A918641D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; 43A918651D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; 43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -771,18 +495,6 @@ 43A9186E1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; 43A9186F1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; 43A918701D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; - 43C8929A1D9D6DD70022038D /* anim_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892981D9D6DD70022038D /* anim_decode.c */; }; - 43C8929B1D9D6DD70022038D /* demux.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892991D9D6DD70022038D /* demux.c */; }; - 43C8929C1D9D6DD90022038D /* anim_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892981D9D6DD70022038D /* anim_decode.c */; }; - 43C8929D1D9D6DD90022038D /* anim_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892981D9D6DD70022038D /* anim_decode.c */; }; - 43C8929E1D9D6DDA0022038D /* anim_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892981D9D6DD70022038D /* anim_decode.c */; }; - 43C8929F1D9D6DDA0022038D /* anim_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892981D9D6DD70022038D /* anim_decode.c */; }; - 43C892A01D9D6DDA0022038D /* anim_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892981D9D6DD70022038D /* anim_decode.c */; }; - 43C892A11D9D6DDC0022038D /* demux.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892991D9D6DD70022038D /* demux.c */; }; - 43C892A21D9D6DDD0022038D /* demux.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892991D9D6DD70022038D /* demux.c */; }; - 43C892A31D9D6DDD0022038D /* demux.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892991D9D6DD70022038D /* demux.c */; }; - 43C892A41D9D6DDD0022038D /* demux.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892991D9D6DD70022038D /* demux.c */; }; - 43C892A51D9D6DDE0022038D /* demux.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C892991D9D6DD70022038D /* demux.c */; }; 4A2CAE041AB4BB5400B6BC39 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4A2CAE181AB4BB6400B6BC39 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D88148C56230056699D /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4A2CAE191AB4BB6400B6BC39 /* SDWebImageCompat.m in Sources */ = {isa = PBXBuildFile; fileRef = 5340674F167780C40042B59E /* SDWebImageCompat.m */; }; @@ -835,672 +547,6 @@ 53EDFB8C17623F7C00698166 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */; }; 5D5B9142188EE8DD006D06BD /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5D5B9145188EE8DD006D06BD /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */; }; - 80377BF81F2F665300F89830 /* bit_reader_inl_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BDE1F2F665300F89830 /* bit_reader_inl_utils.h */; }; - 80377BF91F2F665300F89830 /* bit_reader_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BDF1F2F665300F89830 /* bit_reader_utils.c */; }; - 80377BFA1F2F665300F89830 /* bit_reader_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE01F2F665300F89830 /* bit_reader_utils.h */; }; - 80377BFB1F2F665300F89830 /* bit_writer_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE11F2F665300F89830 /* bit_writer_utils.c */; }; - 80377BFC1F2F665300F89830 /* bit_writer_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE21F2F665300F89830 /* bit_writer_utils.h */; }; - 80377BFD1F2F665300F89830 /* color_cache_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE31F2F665300F89830 /* color_cache_utils.c */; }; - 80377BFE1F2F665300F89830 /* color_cache_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE41F2F665300F89830 /* color_cache_utils.h */; }; - 80377BFF1F2F665300F89830 /* endian_inl_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE51F2F665300F89830 /* endian_inl_utils.h */; }; - 80377C001F2F665300F89830 /* filters_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE61F2F665300F89830 /* filters_utils.c */; }; - 80377C011F2F665300F89830 /* filters_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE71F2F665300F89830 /* filters_utils.h */; }; - 80377C021F2F665300F89830 /* huffman_encode_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE81F2F665300F89830 /* huffman_encode_utils.c */; }; - 80377C031F2F665300F89830 /* huffman_encode_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE91F2F665300F89830 /* huffman_encode_utils.h */; }; - 80377C041F2F665300F89830 /* huffman_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEA1F2F665300F89830 /* huffman_utils.c */; }; - 80377C051F2F665300F89830 /* huffman_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BEB1F2F665300F89830 /* huffman_utils.h */; }; - 80377C061F2F665300F89830 /* quant_levels_dec_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEC1F2F665300F89830 /* quant_levels_dec_utils.c */; }; - 80377C071F2F665300F89830 /* quant_levels_dec_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BED1F2F665300F89830 /* quant_levels_dec_utils.h */; }; - 80377C081F2F665300F89830 /* quant_levels_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEE1F2F665300F89830 /* quant_levels_utils.c */; }; - 80377C091F2F665300F89830 /* quant_levels_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BEF1F2F665300F89830 /* quant_levels_utils.h */; }; - 80377C0A1F2F665300F89830 /* random_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF01F2F665300F89830 /* random_utils.c */; }; - 80377C0B1F2F665300F89830 /* random_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF11F2F665300F89830 /* random_utils.h */; }; - 80377C0C1F2F665300F89830 /* rescaler_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF21F2F665300F89830 /* rescaler_utils.c */; }; - 80377C0D1F2F665300F89830 /* rescaler_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF31F2F665300F89830 /* rescaler_utils.h */; }; - 80377C0E1F2F665300F89830 /* thread_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF41F2F665300F89830 /* thread_utils.c */; }; - 80377C0F1F2F665300F89830 /* thread_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF51F2F665300F89830 /* thread_utils.h */; }; - 80377C101F2F665300F89830 /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF61F2F665300F89830 /* utils.c */; }; - 80377C111F2F665300F89830 /* utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF71F2F665300F89830 /* utils.h */; }; - 80377C121F2F666300F89830 /* bit_reader_inl_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BDE1F2F665300F89830 /* bit_reader_inl_utils.h */; }; - 80377C131F2F666300F89830 /* bit_reader_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BDF1F2F665300F89830 /* bit_reader_utils.c */; }; - 80377C141F2F666300F89830 /* bit_reader_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE01F2F665300F89830 /* bit_reader_utils.h */; }; - 80377C151F2F666300F89830 /* bit_writer_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE11F2F665300F89830 /* bit_writer_utils.c */; }; - 80377C161F2F666300F89830 /* bit_writer_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE21F2F665300F89830 /* bit_writer_utils.h */; }; - 80377C171F2F666300F89830 /* color_cache_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE31F2F665300F89830 /* color_cache_utils.c */; }; - 80377C181F2F666300F89830 /* color_cache_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE41F2F665300F89830 /* color_cache_utils.h */; }; - 80377C191F2F666300F89830 /* endian_inl_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE51F2F665300F89830 /* endian_inl_utils.h */; }; - 80377C1A1F2F666300F89830 /* filters_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE61F2F665300F89830 /* filters_utils.c */; }; - 80377C1B1F2F666300F89830 /* filters_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE71F2F665300F89830 /* filters_utils.h */; }; - 80377C1C1F2F666300F89830 /* huffman_encode_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE81F2F665300F89830 /* huffman_encode_utils.c */; }; - 80377C1D1F2F666300F89830 /* huffman_encode_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE91F2F665300F89830 /* huffman_encode_utils.h */; }; - 80377C1E1F2F666300F89830 /* huffman_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEA1F2F665300F89830 /* huffman_utils.c */; }; - 80377C1F1F2F666300F89830 /* huffman_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BEB1F2F665300F89830 /* huffman_utils.h */; }; - 80377C201F2F666300F89830 /* quant_levels_dec_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEC1F2F665300F89830 /* quant_levels_dec_utils.c */; }; - 80377C211F2F666300F89830 /* quant_levels_dec_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BED1F2F665300F89830 /* quant_levels_dec_utils.h */; }; - 80377C221F2F666300F89830 /* quant_levels_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEE1F2F665300F89830 /* quant_levels_utils.c */; }; - 80377C231F2F666300F89830 /* quant_levels_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BEF1F2F665300F89830 /* quant_levels_utils.h */; }; - 80377C241F2F666300F89830 /* random_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF01F2F665300F89830 /* random_utils.c */; }; - 80377C251F2F666300F89830 /* random_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF11F2F665300F89830 /* random_utils.h */; }; - 80377C261F2F666300F89830 /* rescaler_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF21F2F665300F89830 /* rescaler_utils.c */; }; - 80377C271F2F666300F89830 /* rescaler_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF31F2F665300F89830 /* rescaler_utils.h */; }; - 80377C281F2F666300F89830 /* thread_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF41F2F665300F89830 /* thread_utils.c */; }; - 80377C291F2F666300F89830 /* thread_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF51F2F665300F89830 /* thread_utils.h */; }; - 80377C2A1F2F666300F89830 /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF61F2F665300F89830 /* utils.c */; }; - 80377C2B1F2F666300F89830 /* utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF71F2F665300F89830 /* utils.h */; }; - 80377C2C1F2F666300F89830 /* bit_reader_inl_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BDE1F2F665300F89830 /* bit_reader_inl_utils.h */; }; - 80377C2D1F2F666300F89830 /* bit_reader_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BDF1F2F665300F89830 /* bit_reader_utils.c */; }; - 80377C2E1F2F666300F89830 /* bit_reader_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE01F2F665300F89830 /* bit_reader_utils.h */; }; - 80377C2F1F2F666300F89830 /* bit_writer_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE11F2F665300F89830 /* bit_writer_utils.c */; }; - 80377C301F2F666300F89830 /* bit_writer_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE21F2F665300F89830 /* bit_writer_utils.h */; }; - 80377C311F2F666300F89830 /* color_cache_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE31F2F665300F89830 /* color_cache_utils.c */; }; - 80377C321F2F666300F89830 /* color_cache_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE41F2F665300F89830 /* color_cache_utils.h */; }; - 80377C331F2F666300F89830 /* endian_inl_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE51F2F665300F89830 /* endian_inl_utils.h */; }; - 80377C341F2F666300F89830 /* filters_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE61F2F665300F89830 /* filters_utils.c */; }; - 80377C351F2F666300F89830 /* filters_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE71F2F665300F89830 /* filters_utils.h */; }; - 80377C361F2F666300F89830 /* huffman_encode_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE81F2F665300F89830 /* huffman_encode_utils.c */; }; - 80377C371F2F666300F89830 /* huffman_encode_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE91F2F665300F89830 /* huffman_encode_utils.h */; }; - 80377C381F2F666300F89830 /* huffman_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEA1F2F665300F89830 /* huffman_utils.c */; }; - 80377C391F2F666300F89830 /* huffman_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BEB1F2F665300F89830 /* huffman_utils.h */; }; - 80377C3A1F2F666300F89830 /* quant_levels_dec_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEC1F2F665300F89830 /* quant_levels_dec_utils.c */; }; - 80377C3B1F2F666300F89830 /* quant_levels_dec_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BED1F2F665300F89830 /* quant_levels_dec_utils.h */; }; - 80377C3C1F2F666300F89830 /* quant_levels_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEE1F2F665300F89830 /* quant_levels_utils.c */; }; - 80377C3D1F2F666300F89830 /* quant_levels_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BEF1F2F665300F89830 /* quant_levels_utils.h */; }; - 80377C3E1F2F666300F89830 /* random_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF01F2F665300F89830 /* random_utils.c */; }; - 80377C3F1F2F666300F89830 /* random_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF11F2F665300F89830 /* random_utils.h */; }; - 80377C401F2F666300F89830 /* rescaler_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF21F2F665300F89830 /* rescaler_utils.c */; }; - 80377C411F2F666300F89830 /* rescaler_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF31F2F665300F89830 /* rescaler_utils.h */; }; - 80377C421F2F666300F89830 /* thread_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF41F2F665300F89830 /* thread_utils.c */; }; - 80377C431F2F666300F89830 /* thread_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF51F2F665300F89830 /* thread_utils.h */; }; - 80377C441F2F666300F89830 /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF61F2F665300F89830 /* utils.c */; }; - 80377C451F2F666300F89830 /* utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF71F2F665300F89830 /* utils.h */; }; - 80377C461F2F666300F89830 /* bit_reader_inl_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BDE1F2F665300F89830 /* bit_reader_inl_utils.h */; }; - 80377C471F2F666300F89830 /* bit_reader_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BDF1F2F665300F89830 /* bit_reader_utils.c */; }; - 80377C481F2F666300F89830 /* bit_reader_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE01F2F665300F89830 /* bit_reader_utils.h */; }; - 80377C491F2F666300F89830 /* bit_writer_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE11F2F665300F89830 /* bit_writer_utils.c */; }; - 80377C4A1F2F666300F89830 /* bit_writer_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE21F2F665300F89830 /* bit_writer_utils.h */; }; - 80377C4B1F2F666300F89830 /* color_cache_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE31F2F665300F89830 /* color_cache_utils.c */; }; - 80377C4C1F2F666300F89830 /* color_cache_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE41F2F665300F89830 /* color_cache_utils.h */; }; - 80377C4D1F2F666300F89830 /* endian_inl_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE51F2F665300F89830 /* endian_inl_utils.h */; }; - 80377C4E1F2F666300F89830 /* filters_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE61F2F665300F89830 /* filters_utils.c */; }; - 80377C4F1F2F666300F89830 /* filters_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE71F2F665300F89830 /* filters_utils.h */; }; - 80377C501F2F666300F89830 /* huffman_encode_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE81F2F665300F89830 /* huffman_encode_utils.c */; }; - 80377C511F2F666300F89830 /* huffman_encode_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE91F2F665300F89830 /* huffman_encode_utils.h */; }; - 80377C521F2F666300F89830 /* huffman_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEA1F2F665300F89830 /* huffman_utils.c */; }; - 80377C531F2F666300F89830 /* huffman_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BEB1F2F665300F89830 /* huffman_utils.h */; }; - 80377C541F2F666300F89830 /* quant_levels_dec_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEC1F2F665300F89830 /* quant_levels_dec_utils.c */; }; - 80377C551F2F666300F89830 /* quant_levels_dec_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BED1F2F665300F89830 /* quant_levels_dec_utils.h */; }; - 80377C561F2F666300F89830 /* quant_levels_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEE1F2F665300F89830 /* quant_levels_utils.c */; }; - 80377C571F2F666300F89830 /* quant_levels_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BEF1F2F665300F89830 /* quant_levels_utils.h */; }; - 80377C581F2F666300F89830 /* random_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF01F2F665300F89830 /* random_utils.c */; }; - 80377C591F2F666300F89830 /* random_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF11F2F665300F89830 /* random_utils.h */; }; - 80377C5A1F2F666300F89830 /* rescaler_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF21F2F665300F89830 /* rescaler_utils.c */; }; - 80377C5B1F2F666300F89830 /* rescaler_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF31F2F665300F89830 /* rescaler_utils.h */; }; - 80377C5C1F2F666300F89830 /* thread_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF41F2F665300F89830 /* thread_utils.c */; }; - 80377C5D1F2F666300F89830 /* thread_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF51F2F665300F89830 /* thread_utils.h */; }; - 80377C5E1F2F666300F89830 /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF61F2F665300F89830 /* utils.c */; }; - 80377C5F1F2F666300F89830 /* utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF71F2F665300F89830 /* utils.h */; }; - 80377C601F2F666400F89830 /* bit_reader_inl_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BDE1F2F665300F89830 /* bit_reader_inl_utils.h */; }; - 80377C611F2F666400F89830 /* bit_reader_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BDF1F2F665300F89830 /* bit_reader_utils.c */; }; - 80377C621F2F666400F89830 /* bit_reader_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE01F2F665300F89830 /* bit_reader_utils.h */; }; - 80377C631F2F666400F89830 /* bit_writer_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE11F2F665300F89830 /* bit_writer_utils.c */; }; - 80377C641F2F666400F89830 /* bit_writer_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE21F2F665300F89830 /* bit_writer_utils.h */; }; - 80377C651F2F666400F89830 /* color_cache_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE31F2F665300F89830 /* color_cache_utils.c */; }; - 80377C661F2F666400F89830 /* color_cache_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE41F2F665300F89830 /* color_cache_utils.h */; }; - 80377C671F2F666400F89830 /* endian_inl_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE51F2F665300F89830 /* endian_inl_utils.h */; }; - 80377C681F2F666400F89830 /* filters_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE61F2F665300F89830 /* filters_utils.c */; }; - 80377C691F2F666400F89830 /* filters_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE71F2F665300F89830 /* filters_utils.h */; }; - 80377C6A1F2F666400F89830 /* huffman_encode_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE81F2F665300F89830 /* huffman_encode_utils.c */; }; - 80377C6B1F2F666400F89830 /* huffman_encode_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE91F2F665300F89830 /* huffman_encode_utils.h */; }; - 80377C6C1F2F666400F89830 /* huffman_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEA1F2F665300F89830 /* huffman_utils.c */; }; - 80377C6D1F2F666400F89830 /* huffman_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BEB1F2F665300F89830 /* huffman_utils.h */; }; - 80377C6E1F2F666400F89830 /* quant_levels_dec_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEC1F2F665300F89830 /* quant_levels_dec_utils.c */; }; - 80377C6F1F2F666400F89830 /* quant_levels_dec_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BED1F2F665300F89830 /* quant_levels_dec_utils.h */; }; - 80377C701F2F666400F89830 /* quant_levels_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEE1F2F665300F89830 /* quant_levels_utils.c */; }; - 80377C711F2F666400F89830 /* quant_levels_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BEF1F2F665300F89830 /* quant_levels_utils.h */; }; - 80377C721F2F666400F89830 /* random_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF01F2F665300F89830 /* random_utils.c */; }; - 80377C731F2F666400F89830 /* random_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF11F2F665300F89830 /* random_utils.h */; }; - 80377C741F2F666400F89830 /* rescaler_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF21F2F665300F89830 /* rescaler_utils.c */; }; - 80377C751F2F666400F89830 /* rescaler_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF31F2F665300F89830 /* rescaler_utils.h */; }; - 80377C761F2F666400F89830 /* thread_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF41F2F665300F89830 /* thread_utils.c */; }; - 80377C771F2F666400F89830 /* thread_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF51F2F665300F89830 /* thread_utils.h */; }; - 80377C781F2F666400F89830 /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF61F2F665300F89830 /* utils.c */; }; - 80377C791F2F666400F89830 /* utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF71F2F665300F89830 /* utils.h */; }; - 80377C7A1F2F666400F89830 /* bit_reader_inl_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BDE1F2F665300F89830 /* bit_reader_inl_utils.h */; }; - 80377C7B1F2F666400F89830 /* bit_reader_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BDF1F2F665300F89830 /* bit_reader_utils.c */; }; - 80377C7C1F2F666400F89830 /* bit_reader_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE01F2F665300F89830 /* bit_reader_utils.h */; }; - 80377C7D1F2F666400F89830 /* bit_writer_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE11F2F665300F89830 /* bit_writer_utils.c */; }; - 80377C7E1F2F666400F89830 /* bit_writer_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE21F2F665300F89830 /* bit_writer_utils.h */; }; - 80377C7F1F2F666400F89830 /* color_cache_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE31F2F665300F89830 /* color_cache_utils.c */; }; - 80377C801F2F666400F89830 /* color_cache_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE41F2F665300F89830 /* color_cache_utils.h */; }; - 80377C811F2F666400F89830 /* endian_inl_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE51F2F665300F89830 /* endian_inl_utils.h */; }; - 80377C821F2F666400F89830 /* filters_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE61F2F665300F89830 /* filters_utils.c */; }; - 80377C831F2F666400F89830 /* filters_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE71F2F665300F89830 /* filters_utils.h */; }; - 80377C841F2F666400F89830 /* huffman_encode_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BE81F2F665300F89830 /* huffman_encode_utils.c */; }; - 80377C851F2F666400F89830 /* huffman_encode_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BE91F2F665300F89830 /* huffman_encode_utils.h */; }; - 80377C861F2F666400F89830 /* huffman_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEA1F2F665300F89830 /* huffman_utils.c */; }; - 80377C871F2F666400F89830 /* huffman_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BEB1F2F665300F89830 /* huffman_utils.h */; }; - 80377C881F2F666400F89830 /* quant_levels_dec_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEC1F2F665300F89830 /* quant_levels_dec_utils.c */; }; - 80377C891F2F666400F89830 /* quant_levels_dec_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BED1F2F665300F89830 /* quant_levels_dec_utils.h */; }; - 80377C8A1F2F666400F89830 /* quant_levels_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BEE1F2F665300F89830 /* quant_levels_utils.c */; }; - 80377C8B1F2F666400F89830 /* quant_levels_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BEF1F2F665300F89830 /* quant_levels_utils.h */; }; - 80377C8C1F2F666400F89830 /* random_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF01F2F665300F89830 /* random_utils.c */; }; - 80377C8D1F2F666400F89830 /* random_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF11F2F665300F89830 /* random_utils.h */; }; - 80377C8E1F2F666400F89830 /* rescaler_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF21F2F665300F89830 /* rescaler_utils.c */; }; - 80377C8F1F2F666400F89830 /* rescaler_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF31F2F665300F89830 /* rescaler_utils.h */; }; - 80377C901F2F666400F89830 /* thread_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF41F2F665300F89830 /* thread_utils.c */; }; - 80377C911F2F666400F89830 /* thread_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF51F2F665300F89830 /* thread_utils.h */; }; - 80377C921F2F666400F89830 /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377BF61F2F665300F89830 /* utils.c */; }; - 80377C931F2F666400F89830 /* utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377BF71F2F665300F89830 /* utils.h */; }; - 80377CD91F2F66A100F89830 /* alpha_processing_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C941F2F66A100F89830 /* alpha_processing_mips_dsp_r2.c */; }; - 80377CDA1F2F66A100F89830 /* alpha_processing_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C951F2F66A100F89830 /* alpha_processing_neon.c */; }; - 80377CDB1F2F66A100F89830 /* alpha_processing_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C961F2F66A100F89830 /* alpha_processing_sse2.c */; }; - 80377CDC1F2F66A100F89830 /* alpha_processing_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C971F2F66A100F89830 /* alpha_processing_sse41.c */; }; - 80377CDD1F2F66A100F89830 /* alpha_processing.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C981F2F66A100F89830 /* alpha_processing.c */; }; - 80377CDE1F2F66A100F89830 /* argb_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C991F2F66A100F89830 /* argb_mips_dsp_r2.c */; }; - 80377CDF1F2F66A100F89830 /* argb_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9A1F2F66A100F89830 /* argb_sse2.c */; }; - 80377CE01F2F66A100F89830 /* argb.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9B1F2F66A100F89830 /* argb.c */; }; - 80377CE11F2F66A100F89830 /* common_sse2.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377C9C1F2F66A100F89830 /* common_sse2.h */; }; - 80377CE21F2F66A100F89830 /* cost_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9D1F2F66A100F89830 /* cost_mips_dsp_r2.c */; }; - 80377CE31F2F66A100F89830 /* cost_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9E1F2F66A100F89830 /* cost_mips32.c */; }; - 80377CE41F2F66A100F89830 /* cost_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9F1F2F66A100F89830 /* cost_sse2.c */; }; - 80377CE51F2F66A100F89830 /* cost.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA01F2F66A100F89830 /* cost.c */; }; - 80377CE61F2F66A100F89830 /* cpu.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA11F2F66A100F89830 /* cpu.c */; }; - 80377CE71F2F66A100F89830 /* dec_clip_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA21F2F66A100F89830 /* dec_clip_tables.c */; }; - 80377CE81F2F66A100F89830 /* dec_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA31F2F66A100F89830 /* dec_mips_dsp_r2.c */; }; - 80377CE91F2F66A100F89830 /* dec_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA41F2F66A100F89830 /* dec_mips32.c */; }; - 80377CEA1F2F66A100F89830 /* dec_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA51F2F66A100F89830 /* dec_msa.c */; }; - 80377CEB1F2F66A100F89830 /* dec_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA61F2F66A100F89830 /* dec_neon.c */; }; - 80377CEC1F2F66A100F89830 /* dec_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA71F2F66A100F89830 /* dec_sse2.c */; }; - 80377CED1F2F66A100F89830 /* dec_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA81F2F66A100F89830 /* dec_sse41.c */; }; - 80377CEE1F2F66A100F89830 /* dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA91F2F66A100F89830 /* dec.c */; }; - 80377CEF1F2F66A100F89830 /* dsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CAA1F2F66A100F89830 /* dsp.h */; }; - 80377CF01F2F66A100F89830 /* enc_avx2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAB1F2F66A100F89830 /* enc_avx2.c */; }; - 80377CF11F2F66A100F89830 /* enc_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAC1F2F66A100F89830 /* enc_mips_dsp_r2.c */; }; - 80377CF21F2F66A100F89830 /* enc_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAD1F2F66A100F89830 /* enc_mips32.c */; }; - 80377CF31F2F66A100F89830 /* enc_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAE1F2F66A100F89830 /* enc_msa.c */; }; - 80377CF41F2F66A100F89830 /* enc_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAF1F2F66A100F89830 /* enc_neon.c */; }; - 80377CF51F2F66A100F89830 /* enc_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB01F2F66A100F89830 /* enc_sse2.c */; }; - 80377CF61F2F66A100F89830 /* enc_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB11F2F66A100F89830 /* enc_sse41.c */; }; - 80377CF71F2F66A100F89830 /* enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB21F2F66A100F89830 /* enc.c */; }; - 80377CF81F2F66A100F89830 /* filters_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB31F2F66A100F89830 /* filters_mips_dsp_r2.c */; }; - 80377CF91F2F66A100F89830 /* filters_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB41F2F66A100F89830 /* filters_msa.c */; }; - 80377CFA1F2F66A100F89830 /* filters_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB51F2F66A100F89830 /* filters_neon.c */; }; - 80377CFB1F2F66A100F89830 /* filters_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB61F2F66A100F89830 /* filters_sse2.c */; }; - 80377CFC1F2F66A100F89830 /* filters.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB71F2F66A100F89830 /* filters.c */; }; - 80377CFD1F2F66A100F89830 /* lossless_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CB81F2F66A100F89830 /* lossless_common.h */; }; - 80377CFE1F2F66A100F89830 /* lossless_enc_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB91F2F66A100F89830 /* lossless_enc_mips_dsp_r2.c */; }; - 80377CFF1F2F66A100F89830 /* lossless_enc_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBA1F2F66A100F89830 /* lossless_enc_mips32.c */; }; - 80377D001F2F66A100F89830 /* lossless_enc_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBB1F2F66A100F89830 /* lossless_enc_msa.c */; }; - 80377D011F2F66A100F89830 /* lossless_enc_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBC1F2F66A100F89830 /* lossless_enc_neon.c */; }; - 80377D021F2F66A100F89830 /* lossless_enc_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBD1F2F66A100F89830 /* lossless_enc_sse2.c */; }; - 80377D031F2F66A100F89830 /* lossless_enc_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBE1F2F66A100F89830 /* lossless_enc_sse41.c */; }; - 80377D041F2F66A100F89830 /* lossless_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBF1F2F66A100F89830 /* lossless_enc.c */; }; - 80377D051F2F66A100F89830 /* lossless_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC01F2F66A100F89830 /* lossless_mips_dsp_r2.c */; }; - 80377D061F2F66A100F89830 /* lossless_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC11F2F66A100F89830 /* lossless_msa.c */; }; - 80377D071F2F66A100F89830 /* lossless_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC21F2F66A100F89830 /* lossless_neon.c */; }; - 80377D081F2F66A100F89830 /* lossless_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC31F2F66A100F89830 /* lossless_sse2.c */; }; - 80377D091F2F66A100F89830 /* lossless.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC41F2F66A100F89830 /* lossless.c */; }; - 80377D0A1F2F66A100F89830 /* lossless.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC51F2F66A100F89830 /* lossless.h */; }; - 80377D0B1F2F66A100F89830 /* mips_macro.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC61F2F66A100F89830 /* mips_macro.h */; }; - 80377D0C1F2F66A100F89830 /* msa_macro.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC71F2F66A100F89830 /* msa_macro.h */; }; - 80377D0D1F2F66A100F89830 /* neon.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC81F2F66A100F89830 /* neon.h */; }; - 80377D0E1F2F66A100F89830 /* rescaler_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC91F2F66A100F89830 /* rescaler_mips_dsp_r2.c */; }; - 80377D0F1F2F66A100F89830 /* rescaler_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCA1F2F66A100F89830 /* rescaler_mips32.c */; }; - 80377D101F2F66A100F89830 /* rescaler_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCB1F2F66A100F89830 /* rescaler_msa.c */; }; - 80377D111F2F66A100F89830 /* rescaler_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCC1F2F66A100F89830 /* rescaler_neon.c */; }; - 80377D121F2F66A100F89830 /* rescaler_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCD1F2F66A100F89830 /* rescaler_sse2.c */; }; - 80377D131F2F66A100F89830 /* rescaler.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCE1F2F66A100F89830 /* rescaler.c */; }; - 80377D141F2F66A100F89830 /* upsampling_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCF1F2F66A100F89830 /* upsampling_mips_dsp_r2.c */; }; - 80377D151F2F66A100F89830 /* upsampling_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD01F2F66A100F89830 /* upsampling_msa.c */; }; - 80377D161F2F66A100F89830 /* upsampling_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD11F2F66A100F89830 /* upsampling_neon.c */; }; - 80377D171F2F66A100F89830 /* upsampling_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD21F2F66A100F89830 /* upsampling_sse2.c */; }; - 80377D181F2F66A100F89830 /* upsampling.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD31F2F66A100F89830 /* upsampling.c */; }; - 80377D191F2F66A100F89830 /* yuv_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD41F2F66A100F89830 /* yuv_mips_dsp_r2.c */; }; - 80377D1A1F2F66A100F89830 /* yuv_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD51F2F66A100F89830 /* yuv_mips32.c */; }; - 80377D1B1F2F66A100F89830 /* yuv_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD61F2F66A100F89830 /* yuv_sse2.c */; }; - 80377D1C1F2F66A100F89830 /* yuv.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD71F2F66A100F89830 /* yuv.c */; }; - 80377D1D1F2F66A100F89830 /* yuv.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CD81F2F66A100F89830 /* yuv.h */; }; - 80377D1E1F2F66A700F89830 /* alpha_processing_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C941F2F66A100F89830 /* alpha_processing_mips_dsp_r2.c */; }; - 80377D1F1F2F66A700F89830 /* alpha_processing_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C951F2F66A100F89830 /* alpha_processing_neon.c */; }; - 80377D201F2F66A700F89830 /* alpha_processing_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C961F2F66A100F89830 /* alpha_processing_sse2.c */; }; - 80377D211F2F66A700F89830 /* alpha_processing_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C971F2F66A100F89830 /* alpha_processing_sse41.c */; }; - 80377D221F2F66A700F89830 /* alpha_processing.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C981F2F66A100F89830 /* alpha_processing.c */; }; - 80377D231F2F66A700F89830 /* argb_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C991F2F66A100F89830 /* argb_mips_dsp_r2.c */; }; - 80377D241F2F66A700F89830 /* argb_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9A1F2F66A100F89830 /* argb_sse2.c */; }; - 80377D251F2F66A700F89830 /* argb.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9B1F2F66A100F89830 /* argb.c */; }; - 80377D261F2F66A700F89830 /* common_sse2.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377C9C1F2F66A100F89830 /* common_sse2.h */; }; - 80377D271F2F66A700F89830 /* cost_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9D1F2F66A100F89830 /* cost_mips_dsp_r2.c */; }; - 80377D281F2F66A700F89830 /* cost_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9E1F2F66A100F89830 /* cost_mips32.c */; }; - 80377D291F2F66A700F89830 /* cost_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9F1F2F66A100F89830 /* cost_sse2.c */; }; - 80377D2A1F2F66A700F89830 /* cost.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA01F2F66A100F89830 /* cost.c */; }; - 80377D2B1F2F66A700F89830 /* cpu.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA11F2F66A100F89830 /* cpu.c */; }; - 80377D2C1F2F66A700F89830 /* dec_clip_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA21F2F66A100F89830 /* dec_clip_tables.c */; }; - 80377D2D1F2F66A700F89830 /* dec_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA31F2F66A100F89830 /* dec_mips_dsp_r2.c */; }; - 80377D2E1F2F66A700F89830 /* dec_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA41F2F66A100F89830 /* dec_mips32.c */; }; - 80377D2F1F2F66A700F89830 /* dec_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA51F2F66A100F89830 /* dec_msa.c */; }; - 80377D301F2F66A700F89830 /* dec_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA61F2F66A100F89830 /* dec_neon.c */; }; - 80377D311F2F66A700F89830 /* dec_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA71F2F66A100F89830 /* dec_sse2.c */; }; - 80377D321F2F66A700F89830 /* dec_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA81F2F66A100F89830 /* dec_sse41.c */; }; - 80377D331F2F66A700F89830 /* dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA91F2F66A100F89830 /* dec.c */; }; - 80377D341F2F66A700F89830 /* dsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CAA1F2F66A100F89830 /* dsp.h */; }; - 80377D351F2F66A700F89830 /* enc_avx2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAB1F2F66A100F89830 /* enc_avx2.c */; }; - 80377D361F2F66A700F89830 /* enc_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAC1F2F66A100F89830 /* enc_mips_dsp_r2.c */; }; - 80377D371F2F66A700F89830 /* enc_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAD1F2F66A100F89830 /* enc_mips32.c */; }; - 80377D381F2F66A700F89830 /* enc_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAE1F2F66A100F89830 /* enc_msa.c */; }; - 80377D391F2F66A700F89830 /* enc_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAF1F2F66A100F89830 /* enc_neon.c */; }; - 80377D3A1F2F66A700F89830 /* enc_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB01F2F66A100F89830 /* enc_sse2.c */; }; - 80377D3B1F2F66A700F89830 /* enc_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB11F2F66A100F89830 /* enc_sse41.c */; }; - 80377D3C1F2F66A700F89830 /* enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB21F2F66A100F89830 /* enc.c */; }; - 80377D3D1F2F66A700F89830 /* filters_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB31F2F66A100F89830 /* filters_mips_dsp_r2.c */; }; - 80377D3E1F2F66A700F89830 /* filters_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB41F2F66A100F89830 /* filters_msa.c */; }; - 80377D3F1F2F66A700F89830 /* filters_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB51F2F66A100F89830 /* filters_neon.c */; }; - 80377D401F2F66A700F89830 /* filters_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB61F2F66A100F89830 /* filters_sse2.c */; }; - 80377D411F2F66A700F89830 /* filters.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB71F2F66A100F89830 /* filters.c */; }; - 80377D421F2F66A700F89830 /* lossless_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CB81F2F66A100F89830 /* lossless_common.h */; }; - 80377D431F2F66A700F89830 /* lossless_enc_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB91F2F66A100F89830 /* lossless_enc_mips_dsp_r2.c */; }; - 80377D441F2F66A700F89830 /* lossless_enc_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBA1F2F66A100F89830 /* lossless_enc_mips32.c */; }; - 80377D451F2F66A700F89830 /* lossless_enc_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBB1F2F66A100F89830 /* lossless_enc_msa.c */; }; - 80377D461F2F66A700F89830 /* lossless_enc_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBC1F2F66A100F89830 /* lossless_enc_neon.c */; }; - 80377D471F2F66A700F89830 /* lossless_enc_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBD1F2F66A100F89830 /* lossless_enc_sse2.c */; }; - 80377D481F2F66A700F89830 /* lossless_enc_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBE1F2F66A100F89830 /* lossless_enc_sse41.c */; }; - 80377D491F2F66A700F89830 /* lossless_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBF1F2F66A100F89830 /* lossless_enc.c */; }; - 80377D4A1F2F66A700F89830 /* lossless_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC01F2F66A100F89830 /* lossless_mips_dsp_r2.c */; }; - 80377D4B1F2F66A700F89830 /* lossless_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC11F2F66A100F89830 /* lossless_msa.c */; }; - 80377D4C1F2F66A700F89830 /* lossless_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC21F2F66A100F89830 /* lossless_neon.c */; }; - 80377D4D1F2F66A700F89830 /* lossless_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC31F2F66A100F89830 /* lossless_sse2.c */; }; - 80377D4E1F2F66A700F89830 /* lossless.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC41F2F66A100F89830 /* lossless.c */; }; - 80377D4F1F2F66A700F89830 /* lossless.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC51F2F66A100F89830 /* lossless.h */; }; - 80377D501F2F66A700F89830 /* mips_macro.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC61F2F66A100F89830 /* mips_macro.h */; }; - 80377D511F2F66A700F89830 /* msa_macro.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC71F2F66A100F89830 /* msa_macro.h */; }; - 80377D521F2F66A700F89830 /* neon.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC81F2F66A100F89830 /* neon.h */; }; - 80377D531F2F66A700F89830 /* rescaler_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC91F2F66A100F89830 /* rescaler_mips_dsp_r2.c */; }; - 80377D541F2F66A700F89830 /* rescaler_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCA1F2F66A100F89830 /* rescaler_mips32.c */; }; - 80377D551F2F66A700F89830 /* rescaler_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCB1F2F66A100F89830 /* rescaler_msa.c */; }; - 80377D561F2F66A700F89830 /* rescaler_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCC1F2F66A100F89830 /* rescaler_neon.c */; }; - 80377D571F2F66A700F89830 /* rescaler_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCD1F2F66A100F89830 /* rescaler_sse2.c */; }; - 80377D581F2F66A700F89830 /* rescaler.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCE1F2F66A100F89830 /* rescaler.c */; }; - 80377D591F2F66A700F89830 /* upsampling_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCF1F2F66A100F89830 /* upsampling_mips_dsp_r2.c */; }; - 80377D5A1F2F66A700F89830 /* upsampling_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD01F2F66A100F89830 /* upsampling_msa.c */; }; - 80377D5B1F2F66A700F89830 /* upsampling_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD11F2F66A100F89830 /* upsampling_neon.c */; }; - 80377D5C1F2F66A700F89830 /* upsampling_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD21F2F66A100F89830 /* upsampling_sse2.c */; }; - 80377D5D1F2F66A700F89830 /* upsampling.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD31F2F66A100F89830 /* upsampling.c */; }; - 80377D5E1F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD41F2F66A100F89830 /* yuv_mips_dsp_r2.c */; }; - 80377D5F1F2F66A700F89830 /* yuv_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD51F2F66A100F89830 /* yuv_mips32.c */; }; - 80377D601F2F66A700F89830 /* yuv_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD61F2F66A100F89830 /* yuv_sse2.c */; }; - 80377D611F2F66A700F89830 /* yuv.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD71F2F66A100F89830 /* yuv.c */; }; - 80377D621F2F66A700F89830 /* yuv.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CD81F2F66A100F89830 /* yuv.h */; }; - 80377D631F2F66A700F89830 /* alpha_processing_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C941F2F66A100F89830 /* alpha_processing_mips_dsp_r2.c */; }; - 80377D641F2F66A700F89830 /* alpha_processing_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C951F2F66A100F89830 /* alpha_processing_neon.c */; }; - 80377D651F2F66A700F89830 /* alpha_processing_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C961F2F66A100F89830 /* alpha_processing_sse2.c */; }; - 80377D661F2F66A700F89830 /* alpha_processing_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C971F2F66A100F89830 /* alpha_processing_sse41.c */; }; - 80377D671F2F66A700F89830 /* alpha_processing.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C981F2F66A100F89830 /* alpha_processing.c */; }; - 80377D681F2F66A700F89830 /* argb_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C991F2F66A100F89830 /* argb_mips_dsp_r2.c */; }; - 80377D691F2F66A700F89830 /* argb_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9A1F2F66A100F89830 /* argb_sse2.c */; }; - 80377D6A1F2F66A700F89830 /* argb.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9B1F2F66A100F89830 /* argb.c */; }; - 80377D6B1F2F66A700F89830 /* common_sse2.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377C9C1F2F66A100F89830 /* common_sse2.h */; }; - 80377D6C1F2F66A700F89830 /* cost_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9D1F2F66A100F89830 /* cost_mips_dsp_r2.c */; }; - 80377D6D1F2F66A700F89830 /* cost_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9E1F2F66A100F89830 /* cost_mips32.c */; }; - 80377D6E1F2F66A700F89830 /* cost_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9F1F2F66A100F89830 /* cost_sse2.c */; }; - 80377D6F1F2F66A700F89830 /* cost.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA01F2F66A100F89830 /* cost.c */; }; - 80377D701F2F66A700F89830 /* cpu.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA11F2F66A100F89830 /* cpu.c */; }; - 80377D711F2F66A700F89830 /* dec_clip_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA21F2F66A100F89830 /* dec_clip_tables.c */; }; - 80377D721F2F66A700F89830 /* dec_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA31F2F66A100F89830 /* dec_mips_dsp_r2.c */; }; - 80377D731F2F66A700F89830 /* dec_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA41F2F66A100F89830 /* dec_mips32.c */; }; - 80377D741F2F66A700F89830 /* dec_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA51F2F66A100F89830 /* dec_msa.c */; }; - 80377D751F2F66A700F89830 /* dec_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA61F2F66A100F89830 /* dec_neon.c */; }; - 80377D761F2F66A700F89830 /* dec_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA71F2F66A100F89830 /* dec_sse2.c */; }; - 80377D771F2F66A700F89830 /* dec_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA81F2F66A100F89830 /* dec_sse41.c */; }; - 80377D781F2F66A700F89830 /* dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA91F2F66A100F89830 /* dec.c */; }; - 80377D791F2F66A700F89830 /* dsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CAA1F2F66A100F89830 /* dsp.h */; }; - 80377D7A1F2F66A700F89830 /* enc_avx2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAB1F2F66A100F89830 /* enc_avx2.c */; }; - 80377D7B1F2F66A700F89830 /* enc_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAC1F2F66A100F89830 /* enc_mips_dsp_r2.c */; }; - 80377D7C1F2F66A700F89830 /* enc_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAD1F2F66A100F89830 /* enc_mips32.c */; }; - 80377D7D1F2F66A700F89830 /* enc_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAE1F2F66A100F89830 /* enc_msa.c */; }; - 80377D7E1F2F66A700F89830 /* enc_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAF1F2F66A100F89830 /* enc_neon.c */; }; - 80377D7F1F2F66A700F89830 /* enc_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB01F2F66A100F89830 /* enc_sse2.c */; }; - 80377D801F2F66A700F89830 /* enc_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB11F2F66A100F89830 /* enc_sse41.c */; }; - 80377D811F2F66A700F89830 /* enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB21F2F66A100F89830 /* enc.c */; }; - 80377D821F2F66A700F89830 /* filters_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB31F2F66A100F89830 /* filters_mips_dsp_r2.c */; }; - 80377D831F2F66A700F89830 /* filters_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB41F2F66A100F89830 /* filters_msa.c */; }; - 80377D841F2F66A700F89830 /* filters_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB51F2F66A100F89830 /* filters_neon.c */; }; - 80377D851F2F66A700F89830 /* filters_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB61F2F66A100F89830 /* filters_sse2.c */; }; - 80377D861F2F66A700F89830 /* filters.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB71F2F66A100F89830 /* filters.c */; }; - 80377D871F2F66A700F89830 /* lossless_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CB81F2F66A100F89830 /* lossless_common.h */; }; - 80377D881F2F66A700F89830 /* lossless_enc_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB91F2F66A100F89830 /* lossless_enc_mips_dsp_r2.c */; }; - 80377D891F2F66A700F89830 /* lossless_enc_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBA1F2F66A100F89830 /* lossless_enc_mips32.c */; }; - 80377D8A1F2F66A700F89830 /* lossless_enc_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBB1F2F66A100F89830 /* lossless_enc_msa.c */; }; - 80377D8B1F2F66A700F89830 /* lossless_enc_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBC1F2F66A100F89830 /* lossless_enc_neon.c */; }; - 80377D8C1F2F66A700F89830 /* lossless_enc_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBD1F2F66A100F89830 /* lossless_enc_sse2.c */; }; - 80377D8D1F2F66A700F89830 /* lossless_enc_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBE1F2F66A100F89830 /* lossless_enc_sse41.c */; }; - 80377D8E1F2F66A700F89830 /* lossless_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBF1F2F66A100F89830 /* lossless_enc.c */; }; - 80377D8F1F2F66A700F89830 /* lossless_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC01F2F66A100F89830 /* lossless_mips_dsp_r2.c */; }; - 80377D901F2F66A700F89830 /* lossless_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC11F2F66A100F89830 /* lossless_msa.c */; }; - 80377D911F2F66A700F89830 /* lossless_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC21F2F66A100F89830 /* lossless_neon.c */; }; - 80377D921F2F66A700F89830 /* lossless_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC31F2F66A100F89830 /* lossless_sse2.c */; }; - 80377D931F2F66A700F89830 /* lossless.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC41F2F66A100F89830 /* lossless.c */; }; - 80377D941F2F66A700F89830 /* lossless.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC51F2F66A100F89830 /* lossless.h */; }; - 80377D951F2F66A700F89830 /* mips_macro.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC61F2F66A100F89830 /* mips_macro.h */; }; - 80377D961F2F66A700F89830 /* msa_macro.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC71F2F66A100F89830 /* msa_macro.h */; }; - 80377D971F2F66A700F89830 /* neon.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC81F2F66A100F89830 /* neon.h */; }; - 80377D981F2F66A700F89830 /* rescaler_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC91F2F66A100F89830 /* rescaler_mips_dsp_r2.c */; }; - 80377D991F2F66A700F89830 /* rescaler_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCA1F2F66A100F89830 /* rescaler_mips32.c */; }; - 80377D9A1F2F66A700F89830 /* rescaler_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCB1F2F66A100F89830 /* rescaler_msa.c */; }; - 80377D9B1F2F66A700F89830 /* rescaler_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCC1F2F66A100F89830 /* rescaler_neon.c */; }; - 80377D9C1F2F66A700F89830 /* rescaler_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCD1F2F66A100F89830 /* rescaler_sse2.c */; }; - 80377D9D1F2F66A700F89830 /* rescaler.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCE1F2F66A100F89830 /* rescaler.c */; }; - 80377D9E1F2F66A700F89830 /* upsampling_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCF1F2F66A100F89830 /* upsampling_mips_dsp_r2.c */; }; - 80377D9F1F2F66A700F89830 /* upsampling_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD01F2F66A100F89830 /* upsampling_msa.c */; }; - 80377DA01F2F66A700F89830 /* upsampling_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD11F2F66A100F89830 /* upsampling_neon.c */; }; - 80377DA11F2F66A700F89830 /* upsampling_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD21F2F66A100F89830 /* upsampling_sse2.c */; }; - 80377DA21F2F66A700F89830 /* upsampling.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD31F2F66A100F89830 /* upsampling.c */; }; - 80377DA31F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD41F2F66A100F89830 /* yuv_mips_dsp_r2.c */; }; - 80377DA41F2F66A700F89830 /* yuv_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD51F2F66A100F89830 /* yuv_mips32.c */; }; - 80377DA51F2F66A700F89830 /* yuv_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD61F2F66A100F89830 /* yuv_sse2.c */; }; - 80377DA61F2F66A700F89830 /* yuv.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD71F2F66A100F89830 /* yuv.c */; }; - 80377DA71F2F66A700F89830 /* yuv.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CD81F2F66A100F89830 /* yuv.h */; }; - 80377DA81F2F66A700F89830 /* alpha_processing_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C941F2F66A100F89830 /* alpha_processing_mips_dsp_r2.c */; }; - 80377DA91F2F66A700F89830 /* alpha_processing_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C951F2F66A100F89830 /* alpha_processing_neon.c */; }; - 80377DAA1F2F66A700F89830 /* alpha_processing_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C961F2F66A100F89830 /* alpha_processing_sse2.c */; }; - 80377DAB1F2F66A700F89830 /* alpha_processing_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C971F2F66A100F89830 /* alpha_processing_sse41.c */; }; - 80377DAC1F2F66A700F89830 /* alpha_processing.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C981F2F66A100F89830 /* alpha_processing.c */; }; - 80377DAD1F2F66A700F89830 /* argb_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C991F2F66A100F89830 /* argb_mips_dsp_r2.c */; }; - 80377DAE1F2F66A700F89830 /* argb_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9A1F2F66A100F89830 /* argb_sse2.c */; }; - 80377DAF1F2F66A700F89830 /* argb.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9B1F2F66A100F89830 /* argb.c */; }; - 80377DB01F2F66A700F89830 /* common_sse2.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377C9C1F2F66A100F89830 /* common_sse2.h */; }; - 80377DB11F2F66A700F89830 /* cost_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9D1F2F66A100F89830 /* cost_mips_dsp_r2.c */; }; - 80377DB21F2F66A700F89830 /* cost_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9E1F2F66A100F89830 /* cost_mips32.c */; }; - 80377DB31F2F66A700F89830 /* cost_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9F1F2F66A100F89830 /* cost_sse2.c */; }; - 80377DB41F2F66A700F89830 /* cost.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA01F2F66A100F89830 /* cost.c */; }; - 80377DB51F2F66A700F89830 /* cpu.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA11F2F66A100F89830 /* cpu.c */; }; - 80377DB61F2F66A700F89830 /* dec_clip_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA21F2F66A100F89830 /* dec_clip_tables.c */; }; - 80377DB71F2F66A700F89830 /* dec_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA31F2F66A100F89830 /* dec_mips_dsp_r2.c */; }; - 80377DB81F2F66A700F89830 /* dec_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA41F2F66A100F89830 /* dec_mips32.c */; }; - 80377DB91F2F66A700F89830 /* dec_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA51F2F66A100F89830 /* dec_msa.c */; }; - 80377DBA1F2F66A700F89830 /* dec_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA61F2F66A100F89830 /* dec_neon.c */; }; - 80377DBB1F2F66A700F89830 /* dec_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA71F2F66A100F89830 /* dec_sse2.c */; }; - 80377DBC1F2F66A700F89830 /* dec_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA81F2F66A100F89830 /* dec_sse41.c */; }; - 80377DBD1F2F66A700F89830 /* dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA91F2F66A100F89830 /* dec.c */; }; - 80377DBE1F2F66A700F89830 /* dsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CAA1F2F66A100F89830 /* dsp.h */; }; - 80377DBF1F2F66A700F89830 /* enc_avx2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAB1F2F66A100F89830 /* enc_avx2.c */; }; - 80377DC01F2F66A700F89830 /* enc_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAC1F2F66A100F89830 /* enc_mips_dsp_r2.c */; }; - 80377DC11F2F66A700F89830 /* enc_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAD1F2F66A100F89830 /* enc_mips32.c */; }; - 80377DC21F2F66A700F89830 /* enc_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAE1F2F66A100F89830 /* enc_msa.c */; }; - 80377DC31F2F66A700F89830 /* enc_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAF1F2F66A100F89830 /* enc_neon.c */; }; - 80377DC41F2F66A700F89830 /* enc_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB01F2F66A100F89830 /* enc_sse2.c */; }; - 80377DC51F2F66A700F89830 /* enc_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB11F2F66A100F89830 /* enc_sse41.c */; }; - 80377DC61F2F66A700F89830 /* enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB21F2F66A100F89830 /* enc.c */; }; - 80377DC71F2F66A700F89830 /* filters_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB31F2F66A100F89830 /* filters_mips_dsp_r2.c */; }; - 80377DC81F2F66A700F89830 /* filters_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB41F2F66A100F89830 /* filters_msa.c */; }; - 80377DC91F2F66A700F89830 /* filters_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB51F2F66A100F89830 /* filters_neon.c */; }; - 80377DCA1F2F66A700F89830 /* filters_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB61F2F66A100F89830 /* filters_sse2.c */; }; - 80377DCB1F2F66A700F89830 /* filters.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB71F2F66A100F89830 /* filters.c */; }; - 80377DCC1F2F66A700F89830 /* lossless_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CB81F2F66A100F89830 /* lossless_common.h */; }; - 80377DCD1F2F66A700F89830 /* lossless_enc_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB91F2F66A100F89830 /* lossless_enc_mips_dsp_r2.c */; }; - 80377DCE1F2F66A700F89830 /* lossless_enc_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBA1F2F66A100F89830 /* lossless_enc_mips32.c */; }; - 80377DCF1F2F66A700F89830 /* lossless_enc_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBB1F2F66A100F89830 /* lossless_enc_msa.c */; }; - 80377DD01F2F66A700F89830 /* lossless_enc_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBC1F2F66A100F89830 /* lossless_enc_neon.c */; }; - 80377DD11F2F66A700F89830 /* lossless_enc_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBD1F2F66A100F89830 /* lossless_enc_sse2.c */; }; - 80377DD21F2F66A700F89830 /* lossless_enc_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBE1F2F66A100F89830 /* lossless_enc_sse41.c */; }; - 80377DD31F2F66A700F89830 /* lossless_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBF1F2F66A100F89830 /* lossless_enc.c */; }; - 80377DD41F2F66A700F89830 /* lossless_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC01F2F66A100F89830 /* lossless_mips_dsp_r2.c */; }; - 80377DD51F2F66A700F89830 /* lossless_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC11F2F66A100F89830 /* lossless_msa.c */; }; - 80377DD61F2F66A700F89830 /* lossless_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC21F2F66A100F89830 /* lossless_neon.c */; }; - 80377DD71F2F66A700F89830 /* lossless_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC31F2F66A100F89830 /* lossless_sse2.c */; }; - 80377DD81F2F66A700F89830 /* lossless.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC41F2F66A100F89830 /* lossless.c */; }; - 80377DD91F2F66A700F89830 /* lossless.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC51F2F66A100F89830 /* lossless.h */; }; - 80377DDA1F2F66A700F89830 /* mips_macro.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC61F2F66A100F89830 /* mips_macro.h */; }; - 80377DDB1F2F66A700F89830 /* msa_macro.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC71F2F66A100F89830 /* msa_macro.h */; }; - 80377DDC1F2F66A700F89830 /* neon.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC81F2F66A100F89830 /* neon.h */; }; - 80377DDD1F2F66A700F89830 /* rescaler_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC91F2F66A100F89830 /* rescaler_mips_dsp_r2.c */; }; - 80377DDE1F2F66A700F89830 /* rescaler_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCA1F2F66A100F89830 /* rescaler_mips32.c */; }; - 80377DDF1F2F66A700F89830 /* rescaler_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCB1F2F66A100F89830 /* rescaler_msa.c */; }; - 80377DE01F2F66A700F89830 /* rescaler_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCC1F2F66A100F89830 /* rescaler_neon.c */; }; - 80377DE11F2F66A700F89830 /* rescaler_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCD1F2F66A100F89830 /* rescaler_sse2.c */; }; - 80377DE21F2F66A700F89830 /* rescaler.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCE1F2F66A100F89830 /* rescaler.c */; }; - 80377DE31F2F66A700F89830 /* upsampling_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCF1F2F66A100F89830 /* upsampling_mips_dsp_r2.c */; }; - 80377DE41F2F66A700F89830 /* upsampling_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD01F2F66A100F89830 /* upsampling_msa.c */; }; - 80377DE51F2F66A700F89830 /* upsampling_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD11F2F66A100F89830 /* upsampling_neon.c */; }; - 80377DE61F2F66A700F89830 /* upsampling_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD21F2F66A100F89830 /* upsampling_sse2.c */; }; - 80377DE71F2F66A700F89830 /* upsampling.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD31F2F66A100F89830 /* upsampling.c */; }; - 80377DE81F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD41F2F66A100F89830 /* yuv_mips_dsp_r2.c */; }; - 80377DE91F2F66A700F89830 /* yuv_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD51F2F66A100F89830 /* yuv_mips32.c */; }; - 80377DEA1F2F66A700F89830 /* yuv_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD61F2F66A100F89830 /* yuv_sse2.c */; }; - 80377DEB1F2F66A700F89830 /* yuv.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD71F2F66A100F89830 /* yuv.c */; }; - 80377DEC1F2F66A700F89830 /* yuv.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CD81F2F66A100F89830 /* yuv.h */; }; - 80377DED1F2F66A800F89830 /* alpha_processing_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C941F2F66A100F89830 /* alpha_processing_mips_dsp_r2.c */; }; - 80377DEE1F2F66A800F89830 /* alpha_processing_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C951F2F66A100F89830 /* alpha_processing_neon.c */; }; - 80377DEF1F2F66A800F89830 /* alpha_processing_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C961F2F66A100F89830 /* alpha_processing_sse2.c */; }; - 80377DF01F2F66A800F89830 /* alpha_processing_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C971F2F66A100F89830 /* alpha_processing_sse41.c */; }; - 80377DF11F2F66A800F89830 /* alpha_processing.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C981F2F66A100F89830 /* alpha_processing.c */; }; - 80377DF21F2F66A800F89830 /* argb_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C991F2F66A100F89830 /* argb_mips_dsp_r2.c */; }; - 80377DF31F2F66A800F89830 /* argb_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9A1F2F66A100F89830 /* argb_sse2.c */; }; - 80377DF41F2F66A800F89830 /* argb.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9B1F2F66A100F89830 /* argb.c */; }; - 80377DF51F2F66A800F89830 /* common_sse2.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377C9C1F2F66A100F89830 /* common_sse2.h */; }; - 80377DF61F2F66A800F89830 /* cost_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9D1F2F66A100F89830 /* cost_mips_dsp_r2.c */; }; - 80377DF71F2F66A800F89830 /* cost_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9E1F2F66A100F89830 /* cost_mips32.c */; }; - 80377DF81F2F66A800F89830 /* cost_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9F1F2F66A100F89830 /* cost_sse2.c */; }; - 80377DF91F2F66A800F89830 /* cost.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA01F2F66A100F89830 /* cost.c */; }; - 80377DFA1F2F66A800F89830 /* cpu.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA11F2F66A100F89830 /* cpu.c */; }; - 80377DFB1F2F66A800F89830 /* dec_clip_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA21F2F66A100F89830 /* dec_clip_tables.c */; }; - 80377DFC1F2F66A800F89830 /* dec_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA31F2F66A100F89830 /* dec_mips_dsp_r2.c */; }; - 80377DFD1F2F66A800F89830 /* dec_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA41F2F66A100F89830 /* dec_mips32.c */; }; - 80377DFE1F2F66A800F89830 /* dec_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA51F2F66A100F89830 /* dec_msa.c */; }; - 80377DFF1F2F66A800F89830 /* dec_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA61F2F66A100F89830 /* dec_neon.c */; }; - 80377E001F2F66A800F89830 /* dec_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA71F2F66A100F89830 /* dec_sse2.c */; }; - 80377E011F2F66A800F89830 /* dec_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA81F2F66A100F89830 /* dec_sse41.c */; }; - 80377E021F2F66A800F89830 /* dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA91F2F66A100F89830 /* dec.c */; }; - 80377E031F2F66A800F89830 /* dsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CAA1F2F66A100F89830 /* dsp.h */; }; - 80377E041F2F66A800F89830 /* enc_avx2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAB1F2F66A100F89830 /* enc_avx2.c */; }; - 80377E051F2F66A800F89830 /* enc_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAC1F2F66A100F89830 /* enc_mips_dsp_r2.c */; }; - 80377E061F2F66A800F89830 /* enc_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAD1F2F66A100F89830 /* enc_mips32.c */; }; - 80377E071F2F66A800F89830 /* enc_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAE1F2F66A100F89830 /* enc_msa.c */; }; - 80377E081F2F66A800F89830 /* enc_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAF1F2F66A100F89830 /* enc_neon.c */; }; - 80377E091F2F66A800F89830 /* enc_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB01F2F66A100F89830 /* enc_sse2.c */; }; - 80377E0A1F2F66A800F89830 /* enc_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB11F2F66A100F89830 /* enc_sse41.c */; }; - 80377E0B1F2F66A800F89830 /* enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB21F2F66A100F89830 /* enc.c */; }; - 80377E0C1F2F66A800F89830 /* filters_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB31F2F66A100F89830 /* filters_mips_dsp_r2.c */; }; - 80377E0D1F2F66A800F89830 /* filters_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB41F2F66A100F89830 /* filters_msa.c */; }; - 80377E0E1F2F66A800F89830 /* filters_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB51F2F66A100F89830 /* filters_neon.c */; }; - 80377E0F1F2F66A800F89830 /* filters_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB61F2F66A100F89830 /* filters_sse2.c */; }; - 80377E101F2F66A800F89830 /* filters.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB71F2F66A100F89830 /* filters.c */; }; - 80377E111F2F66A800F89830 /* lossless_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CB81F2F66A100F89830 /* lossless_common.h */; }; - 80377E121F2F66A800F89830 /* lossless_enc_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB91F2F66A100F89830 /* lossless_enc_mips_dsp_r2.c */; }; - 80377E131F2F66A800F89830 /* lossless_enc_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBA1F2F66A100F89830 /* lossless_enc_mips32.c */; }; - 80377E141F2F66A800F89830 /* lossless_enc_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBB1F2F66A100F89830 /* lossless_enc_msa.c */; }; - 80377E151F2F66A800F89830 /* lossless_enc_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBC1F2F66A100F89830 /* lossless_enc_neon.c */; }; - 80377E161F2F66A800F89830 /* lossless_enc_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBD1F2F66A100F89830 /* lossless_enc_sse2.c */; }; - 80377E171F2F66A800F89830 /* lossless_enc_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBE1F2F66A100F89830 /* lossless_enc_sse41.c */; }; - 80377E181F2F66A800F89830 /* lossless_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBF1F2F66A100F89830 /* lossless_enc.c */; }; - 80377E191F2F66A800F89830 /* lossless_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC01F2F66A100F89830 /* lossless_mips_dsp_r2.c */; }; - 80377E1A1F2F66A800F89830 /* lossless_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC11F2F66A100F89830 /* lossless_msa.c */; }; - 80377E1B1F2F66A800F89830 /* lossless_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC21F2F66A100F89830 /* lossless_neon.c */; }; - 80377E1C1F2F66A800F89830 /* lossless_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC31F2F66A100F89830 /* lossless_sse2.c */; }; - 80377E1D1F2F66A800F89830 /* lossless.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC41F2F66A100F89830 /* lossless.c */; }; - 80377E1E1F2F66A800F89830 /* lossless.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC51F2F66A100F89830 /* lossless.h */; }; - 80377E1F1F2F66A800F89830 /* mips_macro.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC61F2F66A100F89830 /* mips_macro.h */; }; - 80377E201F2F66A800F89830 /* msa_macro.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC71F2F66A100F89830 /* msa_macro.h */; }; - 80377E211F2F66A800F89830 /* neon.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC81F2F66A100F89830 /* neon.h */; }; - 80377E221F2F66A800F89830 /* rescaler_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC91F2F66A100F89830 /* rescaler_mips_dsp_r2.c */; }; - 80377E231F2F66A800F89830 /* rescaler_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCA1F2F66A100F89830 /* rescaler_mips32.c */; }; - 80377E241F2F66A800F89830 /* rescaler_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCB1F2F66A100F89830 /* rescaler_msa.c */; }; - 80377E251F2F66A800F89830 /* rescaler_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCC1F2F66A100F89830 /* rescaler_neon.c */; }; - 80377E261F2F66A800F89830 /* rescaler_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCD1F2F66A100F89830 /* rescaler_sse2.c */; }; - 80377E271F2F66A800F89830 /* rescaler.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCE1F2F66A100F89830 /* rescaler.c */; }; - 80377E281F2F66A800F89830 /* upsampling_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCF1F2F66A100F89830 /* upsampling_mips_dsp_r2.c */; }; - 80377E291F2F66A800F89830 /* upsampling_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD01F2F66A100F89830 /* upsampling_msa.c */; }; - 80377E2A1F2F66A800F89830 /* upsampling_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD11F2F66A100F89830 /* upsampling_neon.c */; }; - 80377E2B1F2F66A800F89830 /* upsampling_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD21F2F66A100F89830 /* upsampling_sse2.c */; }; - 80377E2C1F2F66A800F89830 /* upsampling.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD31F2F66A100F89830 /* upsampling.c */; }; - 80377E2D1F2F66A800F89830 /* yuv_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD41F2F66A100F89830 /* yuv_mips_dsp_r2.c */; }; - 80377E2E1F2F66A800F89830 /* yuv_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD51F2F66A100F89830 /* yuv_mips32.c */; }; - 80377E2F1F2F66A800F89830 /* yuv_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD61F2F66A100F89830 /* yuv_sse2.c */; }; - 80377E301F2F66A800F89830 /* yuv.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD71F2F66A100F89830 /* yuv.c */; }; - 80377E311F2F66A800F89830 /* yuv.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CD81F2F66A100F89830 /* yuv.h */; }; - 80377E321F2F66A800F89830 /* alpha_processing_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C941F2F66A100F89830 /* alpha_processing_mips_dsp_r2.c */; }; - 80377E331F2F66A800F89830 /* alpha_processing_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C951F2F66A100F89830 /* alpha_processing_neon.c */; }; - 80377E341F2F66A800F89830 /* alpha_processing_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C961F2F66A100F89830 /* alpha_processing_sse2.c */; }; - 80377E351F2F66A800F89830 /* alpha_processing_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C971F2F66A100F89830 /* alpha_processing_sse41.c */; }; - 80377E361F2F66A800F89830 /* alpha_processing.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C981F2F66A100F89830 /* alpha_processing.c */; }; - 80377E371F2F66A800F89830 /* argb_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C991F2F66A100F89830 /* argb_mips_dsp_r2.c */; }; - 80377E381F2F66A800F89830 /* argb_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9A1F2F66A100F89830 /* argb_sse2.c */; }; - 80377E391F2F66A800F89830 /* argb.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9B1F2F66A100F89830 /* argb.c */; }; - 80377E3A1F2F66A800F89830 /* common_sse2.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377C9C1F2F66A100F89830 /* common_sse2.h */; }; - 80377E3B1F2F66A800F89830 /* cost_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9D1F2F66A100F89830 /* cost_mips_dsp_r2.c */; }; - 80377E3C1F2F66A800F89830 /* cost_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9E1F2F66A100F89830 /* cost_mips32.c */; }; - 80377E3D1F2F66A800F89830 /* cost_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377C9F1F2F66A100F89830 /* cost_sse2.c */; }; - 80377E3E1F2F66A800F89830 /* cost.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA01F2F66A100F89830 /* cost.c */; }; - 80377E3F1F2F66A800F89830 /* cpu.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA11F2F66A100F89830 /* cpu.c */; }; - 80377E401F2F66A800F89830 /* dec_clip_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA21F2F66A100F89830 /* dec_clip_tables.c */; }; - 80377E411F2F66A800F89830 /* dec_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA31F2F66A100F89830 /* dec_mips_dsp_r2.c */; }; - 80377E421F2F66A800F89830 /* dec_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA41F2F66A100F89830 /* dec_mips32.c */; }; - 80377E431F2F66A800F89830 /* dec_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA51F2F66A100F89830 /* dec_msa.c */; }; - 80377E441F2F66A800F89830 /* dec_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA61F2F66A100F89830 /* dec_neon.c */; }; - 80377E451F2F66A800F89830 /* dec_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA71F2F66A100F89830 /* dec_sse2.c */; }; - 80377E461F2F66A800F89830 /* dec_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA81F2F66A100F89830 /* dec_sse41.c */; }; - 80377E471F2F66A800F89830 /* dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CA91F2F66A100F89830 /* dec.c */; }; - 80377E481F2F66A800F89830 /* dsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CAA1F2F66A100F89830 /* dsp.h */; }; - 80377E491F2F66A800F89830 /* enc_avx2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAB1F2F66A100F89830 /* enc_avx2.c */; }; - 80377E4A1F2F66A800F89830 /* enc_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAC1F2F66A100F89830 /* enc_mips_dsp_r2.c */; }; - 80377E4B1F2F66A800F89830 /* enc_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAD1F2F66A100F89830 /* enc_mips32.c */; }; - 80377E4C1F2F66A800F89830 /* enc_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAE1F2F66A100F89830 /* enc_msa.c */; }; - 80377E4D1F2F66A800F89830 /* enc_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CAF1F2F66A100F89830 /* enc_neon.c */; }; - 80377E4E1F2F66A800F89830 /* enc_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB01F2F66A100F89830 /* enc_sse2.c */; }; - 80377E4F1F2F66A800F89830 /* enc_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB11F2F66A100F89830 /* enc_sse41.c */; }; - 80377E501F2F66A800F89830 /* enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB21F2F66A100F89830 /* enc.c */; }; - 80377E511F2F66A800F89830 /* filters_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB31F2F66A100F89830 /* filters_mips_dsp_r2.c */; }; - 80377E521F2F66A800F89830 /* filters_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB41F2F66A100F89830 /* filters_msa.c */; }; - 80377E531F2F66A800F89830 /* filters_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB51F2F66A100F89830 /* filters_neon.c */; }; - 80377E541F2F66A800F89830 /* filters_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB61F2F66A100F89830 /* filters_sse2.c */; }; - 80377E551F2F66A800F89830 /* filters.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB71F2F66A100F89830 /* filters.c */; }; - 80377E561F2F66A800F89830 /* lossless_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CB81F2F66A100F89830 /* lossless_common.h */; }; - 80377E571F2F66A800F89830 /* lossless_enc_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CB91F2F66A100F89830 /* lossless_enc_mips_dsp_r2.c */; }; - 80377E581F2F66A800F89830 /* lossless_enc_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBA1F2F66A100F89830 /* lossless_enc_mips32.c */; }; - 80377E591F2F66A800F89830 /* lossless_enc_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBB1F2F66A100F89830 /* lossless_enc_msa.c */; }; - 80377E5A1F2F66A800F89830 /* lossless_enc_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBC1F2F66A100F89830 /* lossless_enc_neon.c */; }; - 80377E5B1F2F66A800F89830 /* lossless_enc_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBD1F2F66A100F89830 /* lossless_enc_sse2.c */; }; - 80377E5C1F2F66A800F89830 /* lossless_enc_sse41.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBE1F2F66A100F89830 /* lossless_enc_sse41.c */; }; - 80377E5D1F2F66A800F89830 /* lossless_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CBF1F2F66A100F89830 /* lossless_enc.c */; }; - 80377E5E1F2F66A800F89830 /* lossless_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC01F2F66A100F89830 /* lossless_mips_dsp_r2.c */; }; - 80377E5F1F2F66A800F89830 /* lossless_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC11F2F66A100F89830 /* lossless_msa.c */; }; - 80377E601F2F66A800F89830 /* lossless_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC21F2F66A100F89830 /* lossless_neon.c */; }; - 80377E611F2F66A800F89830 /* lossless_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC31F2F66A100F89830 /* lossless_sse2.c */; }; - 80377E621F2F66A800F89830 /* lossless.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC41F2F66A100F89830 /* lossless.c */; }; - 80377E631F2F66A800F89830 /* lossless.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC51F2F66A100F89830 /* lossless.h */; }; - 80377E641F2F66A800F89830 /* mips_macro.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC61F2F66A100F89830 /* mips_macro.h */; }; - 80377E651F2F66A800F89830 /* msa_macro.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC71F2F66A100F89830 /* msa_macro.h */; }; - 80377E661F2F66A800F89830 /* neon.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CC81F2F66A100F89830 /* neon.h */; }; - 80377E671F2F66A800F89830 /* rescaler_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CC91F2F66A100F89830 /* rescaler_mips_dsp_r2.c */; }; - 80377E681F2F66A800F89830 /* rescaler_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCA1F2F66A100F89830 /* rescaler_mips32.c */; }; - 80377E691F2F66A800F89830 /* rescaler_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCB1F2F66A100F89830 /* rescaler_msa.c */; }; - 80377E6A1F2F66A800F89830 /* rescaler_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCC1F2F66A100F89830 /* rescaler_neon.c */; }; - 80377E6B1F2F66A800F89830 /* rescaler_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCD1F2F66A100F89830 /* rescaler_sse2.c */; }; - 80377E6C1F2F66A800F89830 /* rescaler.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCE1F2F66A100F89830 /* rescaler.c */; }; - 80377E6D1F2F66A800F89830 /* upsampling_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CCF1F2F66A100F89830 /* upsampling_mips_dsp_r2.c */; }; - 80377E6E1F2F66A800F89830 /* upsampling_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD01F2F66A100F89830 /* upsampling_msa.c */; }; - 80377E6F1F2F66A800F89830 /* upsampling_neon.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD11F2F66A100F89830 /* upsampling_neon.c */; }; - 80377E701F2F66A800F89830 /* upsampling_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD21F2F66A100F89830 /* upsampling_sse2.c */; }; - 80377E711F2F66A800F89830 /* upsampling.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD31F2F66A100F89830 /* upsampling.c */; }; - 80377E721F2F66A800F89830 /* yuv_mips_dsp_r2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD41F2F66A100F89830 /* yuv_mips_dsp_r2.c */; }; - 80377E731F2F66A800F89830 /* yuv_mips32.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD51F2F66A100F89830 /* yuv_mips32.c */; }; - 80377E741F2F66A800F89830 /* yuv_sse2.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD61F2F66A100F89830 /* yuv_sse2.c */; }; - 80377E751F2F66A800F89830 /* yuv.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377CD71F2F66A100F89830 /* yuv.c */; }; - 80377E761F2F66A800F89830 /* yuv.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377CD81F2F66A100F89830 /* yuv.h */; }; - 80377E871F2F66D000F89830 /* alpha_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E771F2F66D000F89830 /* alpha_dec.c */; }; - 80377E881F2F66D000F89830 /* alphai_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E781F2F66D000F89830 /* alphai_dec.h */; }; - 80377E891F2F66D000F89830 /* buffer_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E791F2F66D000F89830 /* buffer_dec.c */; }; - 80377E8A1F2F66D000F89830 /* common_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E7A1F2F66D000F89830 /* common_dec.h */; }; - 80377E8B1F2F66D000F89830 /* frame_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7B1F2F66D000F89830 /* frame_dec.c */; }; - 80377E8C1F2F66D000F89830 /* idec_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7C1F2F66D000F89830 /* idec_dec.c */; }; - 80377E8D1F2F66D000F89830 /* io_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7D1F2F66D000F89830 /* io_dec.c */; }; - 80377E8E1F2F66D000F89830 /* quant_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7E1F2F66D000F89830 /* quant_dec.c */; }; - 80377E8F1F2F66D000F89830 /* tree_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7F1F2F66D000F89830 /* tree_dec.c */; }; - 80377E901F2F66D000F89830 /* vp8_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E801F2F66D000F89830 /* vp8_dec.c */; }; - 80377E911F2F66D000F89830 /* vp8_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E811F2F66D000F89830 /* vp8_dec.h */; }; - 80377E921F2F66D000F89830 /* vp8i_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E821F2F66D000F89830 /* vp8i_dec.h */; }; - 80377E931F2F66D000F89830 /* vp8l_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E831F2F66D000F89830 /* vp8l_dec.c */; }; - 80377E941F2F66D000F89830 /* vp8li_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E841F2F66D000F89830 /* vp8li_dec.h */; }; - 80377E951F2F66D000F89830 /* webp_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E851F2F66D000F89830 /* webp_dec.c */; }; - 80377E961F2F66D000F89830 /* webpi_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E861F2F66D000F89830 /* webpi_dec.h */; }; - 80377E971F2F66D400F89830 /* alpha_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E771F2F66D000F89830 /* alpha_dec.c */; }; - 80377E981F2F66D400F89830 /* alphai_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E781F2F66D000F89830 /* alphai_dec.h */; }; - 80377E991F2F66D400F89830 /* buffer_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E791F2F66D000F89830 /* buffer_dec.c */; }; - 80377E9A1F2F66D400F89830 /* common_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E7A1F2F66D000F89830 /* common_dec.h */; }; - 80377E9B1F2F66D400F89830 /* frame_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7B1F2F66D000F89830 /* frame_dec.c */; }; - 80377E9C1F2F66D400F89830 /* idec_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7C1F2F66D000F89830 /* idec_dec.c */; }; - 80377E9D1F2F66D400F89830 /* io_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7D1F2F66D000F89830 /* io_dec.c */; }; - 80377E9E1F2F66D400F89830 /* quant_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7E1F2F66D000F89830 /* quant_dec.c */; }; - 80377E9F1F2F66D400F89830 /* tree_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7F1F2F66D000F89830 /* tree_dec.c */; }; - 80377EA01F2F66D400F89830 /* vp8_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E801F2F66D000F89830 /* vp8_dec.c */; }; - 80377EA11F2F66D400F89830 /* vp8_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E811F2F66D000F89830 /* vp8_dec.h */; }; - 80377EA21F2F66D400F89830 /* vp8i_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E821F2F66D000F89830 /* vp8i_dec.h */; }; - 80377EA31F2F66D400F89830 /* vp8l_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E831F2F66D000F89830 /* vp8l_dec.c */; }; - 80377EA41F2F66D400F89830 /* vp8li_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E841F2F66D000F89830 /* vp8li_dec.h */; }; - 80377EA51F2F66D400F89830 /* webp_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E851F2F66D000F89830 /* webp_dec.c */; }; - 80377EA61F2F66D400F89830 /* webpi_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E861F2F66D000F89830 /* webpi_dec.h */; }; - 80377EA71F2F66D400F89830 /* alpha_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E771F2F66D000F89830 /* alpha_dec.c */; }; - 80377EA81F2F66D400F89830 /* alphai_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E781F2F66D000F89830 /* alphai_dec.h */; }; - 80377EA91F2F66D400F89830 /* buffer_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E791F2F66D000F89830 /* buffer_dec.c */; }; - 80377EAA1F2F66D400F89830 /* common_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E7A1F2F66D000F89830 /* common_dec.h */; }; - 80377EAB1F2F66D400F89830 /* frame_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7B1F2F66D000F89830 /* frame_dec.c */; }; - 80377EAC1F2F66D400F89830 /* idec_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7C1F2F66D000F89830 /* idec_dec.c */; }; - 80377EAD1F2F66D400F89830 /* io_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7D1F2F66D000F89830 /* io_dec.c */; }; - 80377EAE1F2F66D400F89830 /* quant_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7E1F2F66D000F89830 /* quant_dec.c */; }; - 80377EAF1F2F66D400F89830 /* tree_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7F1F2F66D000F89830 /* tree_dec.c */; }; - 80377EB01F2F66D400F89830 /* vp8_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E801F2F66D000F89830 /* vp8_dec.c */; }; - 80377EB11F2F66D400F89830 /* vp8_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E811F2F66D000F89830 /* vp8_dec.h */; }; - 80377EB21F2F66D400F89830 /* vp8i_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E821F2F66D000F89830 /* vp8i_dec.h */; }; - 80377EB31F2F66D400F89830 /* vp8l_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E831F2F66D000F89830 /* vp8l_dec.c */; }; - 80377EB41F2F66D400F89830 /* vp8li_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E841F2F66D000F89830 /* vp8li_dec.h */; }; - 80377EB51F2F66D400F89830 /* webp_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E851F2F66D000F89830 /* webp_dec.c */; }; - 80377EB61F2F66D400F89830 /* webpi_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E861F2F66D000F89830 /* webpi_dec.h */; }; - 80377EB71F2F66D400F89830 /* alpha_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E771F2F66D000F89830 /* alpha_dec.c */; }; - 80377EB81F2F66D400F89830 /* alphai_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E781F2F66D000F89830 /* alphai_dec.h */; }; - 80377EB91F2F66D400F89830 /* buffer_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E791F2F66D000F89830 /* buffer_dec.c */; }; - 80377EBA1F2F66D500F89830 /* common_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E7A1F2F66D000F89830 /* common_dec.h */; }; - 80377EBB1F2F66D500F89830 /* frame_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7B1F2F66D000F89830 /* frame_dec.c */; }; - 80377EBC1F2F66D500F89830 /* idec_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7C1F2F66D000F89830 /* idec_dec.c */; }; - 80377EBD1F2F66D500F89830 /* io_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7D1F2F66D000F89830 /* io_dec.c */; }; - 80377EBE1F2F66D500F89830 /* quant_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7E1F2F66D000F89830 /* quant_dec.c */; }; - 80377EBF1F2F66D500F89830 /* tree_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7F1F2F66D000F89830 /* tree_dec.c */; }; - 80377EC01F2F66D500F89830 /* vp8_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E801F2F66D000F89830 /* vp8_dec.c */; }; - 80377EC11F2F66D500F89830 /* vp8_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E811F2F66D000F89830 /* vp8_dec.h */; }; - 80377EC21F2F66D500F89830 /* vp8i_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E821F2F66D000F89830 /* vp8i_dec.h */; }; - 80377EC31F2F66D500F89830 /* vp8l_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E831F2F66D000F89830 /* vp8l_dec.c */; }; - 80377EC41F2F66D500F89830 /* vp8li_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E841F2F66D000F89830 /* vp8li_dec.h */; }; - 80377EC51F2F66D500F89830 /* webp_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E851F2F66D000F89830 /* webp_dec.c */; }; - 80377EC61F2F66D500F89830 /* webpi_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E861F2F66D000F89830 /* webpi_dec.h */; }; - 80377EC71F2F66D500F89830 /* alpha_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E771F2F66D000F89830 /* alpha_dec.c */; }; - 80377EC81F2F66D500F89830 /* alphai_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E781F2F66D000F89830 /* alphai_dec.h */; }; - 80377EC91F2F66D500F89830 /* buffer_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E791F2F66D000F89830 /* buffer_dec.c */; }; - 80377ECA1F2F66D500F89830 /* common_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E7A1F2F66D000F89830 /* common_dec.h */; }; - 80377ECB1F2F66D500F89830 /* frame_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7B1F2F66D000F89830 /* frame_dec.c */; }; - 80377ECC1F2F66D500F89830 /* idec_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7C1F2F66D000F89830 /* idec_dec.c */; }; - 80377ECD1F2F66D500F89830 /* io_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7D1F2F66D000F89830 /* io_dec.c */; }; - 80377ECE1F2F66D500F89830 /* quant_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7E1F2F66D000F89830 /* quant_dec.c */; }; - 80377ECF1F2F66D500F89830 /* tree_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7F1F2F66D000F89830 /* tree_dec.c */; }; - 80377ED01F2F66D500F89830 /* vp8_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E801F2F66D000F89830 /* vp8_dec.c */; }; - 80377ED11F2F66D500F89830 /* vp8_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E811F2F66D000F89830 /* vp8_dec.h */; }; - 80377ED21F2F66D500F89830 /* vp8i_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E821F2F66D000F89830 /* vp8i_dec.h */; }; - 80377ED31F2F66D500F89830 /* vp8l_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E831F2F66D000F89830 /* vp8l_dec.c */; }; - 80377ED41F2F66D500F89830 /* vp8li_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E841F2F66D000F89830 /* vp8li_dec.h */; }; - 80377ED51F2F66D500F89830 /* webp_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E851F2F66D000F89830 /* webp_dec.c */; }; - 80377ED61F2F66D500F89830 /* webpi_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E861F2F66D000F89830 /* webpi_dec.h */; }; - 80377ED71F2F66D500F89830 /* alpha_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E771F2F66D000F89830 /* alpha_dec.c */; }; - 80377ED81F2F66D500F89830 /* alphai_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E781F2F66D000F89830 /* alphai_dec.h */; }; - 80377ED91F2F66D500F89830 /* buffer_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E791F2F66D000F89830 /* buffer_dec.c */; }; - 80377EDA1F2F66D500F89830 /* common_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E7A1F2F66D000F89830 /* common_dec.h */; }; - 80377EDB1F2F66D500F89830 /* frame_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7B1F2F66D000F89830 /* frame_dec.c */; }; - 80377EDC1F2F66D500F89830 /* idec_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7C1F2F66D000F89830 /* idec_dec.c */; }; - 80377EDD1F2F66D500F89830 /* io_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7D1F2F66D000F89830 /* io_dec.c */; }; - 80377EDE1F2F66D500F89830 /* quant_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7E1F2F66D000F89830 /* quant_dec.c */; }; - 80377EDF1F2F66D500F89830 /* tree_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E7F1F2F66D000F89830 /* tree_dec.c */; }; - 80377EE01F2F66D500F89830 /* vp8_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E801F2F66D000F89830 /* vp8_dec.c */; }; - 80377EE11F2F66D500F89830 /* vp8_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E811F2F66D000F89830 /* vp8_dec.h */; }; - 80377EE21F2F66D500F89830 /* vp8i_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E821F2F66D000F89830 /* vp8i_dec.h */; }; - 80377EE31F2F66D500F89830 /* vp8l_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E831F2F66D000F89830 /* vp8l_dec.c */; }; - 80377EE41F2F66D500F89830 /* vp8li_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E841F2F66D000F89830 /* vp8li_dec.h */; }; - 80377EE51F2F66D500F89830 /* webp_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E851F2F66D000F89830 /* webp_dec.c */; }; - 80377EE61F2F66D500F89830 /* webpi_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E861F2F66D000F89830 /* webpi_dec.h */; }; 807A12281F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 807A12291F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 807A122A1F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1541,41 +587,6 @@ 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageGIFCoder.m; sourceTree = ""; }; 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+ForceDecode.h"; sourceTree = ""; }; 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+ForceDecode.m"; sourceTree = ""; }; - 323F8B131F38EF770092B609 /* alpha_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alpha_enc.c; sourceTree = ""; }; - 323F8B141F38EF770092B609 /* analysis_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = analysis_enc.c; sourceTree = ""; }; - 323F8B151F38EF770092B609 /* backward_references_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = backward_references_enc.c; sourceTree = ""; }; - 323F8B161F38EF770092B609 /* backward_references_enc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = backward_references_enc.h; sourceTree = ""; }; - 323F8B171F38EF770092B609 /* config_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = config_enc.c; sourceTree = ""; }; - 323F8B181F38EF770092B609 /* cost_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cost_enc.c; sourceTree = ""; }; - 323F8B191F38EF770092B609 /* cost_enc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cost_enc.h; sourceTree = ""; }; - 323F8B1A1F38EF770092B609 /* delta_palettization_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = delta_palettization_enc.c; sourceTree = ""; }; - 323F8B1B1F38EF770092B609 /* delta_palettization_enc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = delta_palettization_enc.h; sourceTree = ""; }; - 323F8B1C1F38EF770092B609 /* filter_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filter_enc.c; sourceTree = ""; }; - 323F8B1D1F38EF770092B609 /* frame_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = frame_enc.c; sourceTree = ""; }; - 323F8B1E1F38EF770092B609 /* histogram_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = histogram_enc.c; sourceTree = ""; }; - 323F8B1F1F38EF770092B609 /* histogram_enc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = histogram_enc.h; sourceTree = ""; }; - 323F8B201F38EF770092B609 /* iterator_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iterator_enc.c; sourceTree = ""; }; - 323F8B221F38EF770092B609 /* near_lossless_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = near_lossless_enc.c; sourceTree = ""; }; - 323F8B231F38EF770092B609 /* picture_csp_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = picture_csp_enc.c; sourceTree = ""; }; - 323F8B241F38EF770092B609 /* picture_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = picture_enc.c; sourceTree = ""; }; - 323F8B251F38EF770092B609 /* picture_psnr_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = picture_psnr_enc.c; sourceTree = ""; }; - 323F8B261F38EF770092B609 /* picture_rescale_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = picture_rescale_enc.c; sourceTree = ""; }; - 323F8B271F38EF770092B609 /* picture_tools_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = picture_tools_enc.c; sourceTree = ""; }; - 323F8B281F38EF770092B609 /* predictor_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = predictor_enc.c; sourceTree = ""; }; - 323F8B291F38EF770092B609 /* quant_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = quant_enc.c; sourceTree = ""; }; - 323F8B2A1F38EF770092B609 /* syntax_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = syntax_enc.c; sourceTree = ""; }; - 323F8B2B1F38EF770092B609 /* token_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = token_enc.c; sourceTree = ""; }; - 323F8B2C1F38EF770092B609 /* tree_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tree_enc.c; sourceTree = ""; }; - 323F8B2D1F38EF770092B609 /* vp8i_enc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vp8i_enc.h; sourceTree = ""; }; - 323F8B2E1F38EF770092B609 /* vp8l_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vp8l_enc.c; sourceTree = ""; }; - 323F8B2F1F38EF770092B609 /* vp8li_enc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vp8li_enc.h; sourceTree = ""; }; - 323F8B301F38EF770092B609 /* webp_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = webp_enc.c; sourceTree = ""; }; - 323F8B321F38EF770092B609 /* anim_encode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = anim_encode.c; sourceTree = ""; }; - 323F8B331F38EF770092B609 /* animi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = animi.h; sourceTree = ""; }; - 323F8B3A1F38EF770092B609 /* muxedit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = muxedit.c; sourceTree = ""; }; - 323F8B3B1F38EF770092B609 /* muxi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = muxi.h; sourceTree = ""; }; - 323F8B3C1F38EF770092B609 /* muxinternal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = muxinternal.c; sourceTree = ""; }; - 323F8B3D1F38EF770092B609 /* muxread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = muxread.c; sourceTree = ""; }; 32484757201775F600AF9E5A /* SDAnimatedImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImageView.m; sourceTree = ""; }; 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SDAnimatedImageView+WebCache.h"; sourceTree = ""; }; 32484759201775F600AF9E5A /* SDAnimatedImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDAnimatedImageView.h; sourceTree = ""; }; @@ -1618,10 +629,6 @@ 32F7C07D2030719600873181 /* UIImage+Transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Transform.h"; sourceTree = ""; }; 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MKAnnotationView+WebCache.m"; sourceTree = ""; }; 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MKAnnotationView+WebCache.h"; sourceTree = ""; }; - 32FDE88520888726008D7530 /* UIImage+WebP.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+WebP.m"; sourceTree = ""; }; - 32FDE88620888726008D7530 /* SDImageWebPCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageWebPCoder.h; sourceTree = ""; }; - 32FDE88720888726008D7530 /* UIImage+WebP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+WebP.h"; sourceTree = ""; }; - 32FDE88820888726008D7530 /* SDImageWebPCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageWebPCoder.m; sourceTree = ""; }; 32FDE8A4208887A6008D7530 /* SDWebImage.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = SDWebImage.modulemap; sourceTree = ""; }; 4314D1991D0E0E3B004B36C9 /* libSDWebImage watchOS static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libSDWebImage watchOS static.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 431BB7031D06D2C1006A3455 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1632,8 +639,6 @@ 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSImage+Compatibility.m"; sourceTree = ""; }; 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageCacheConfig.h; sourceTree = ""; }; 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageCacheConfig.m; sourceTree = ""; }; - 43C892981D9D6DD70022038D /* anim_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = anim_decode.c; sourceTree = ""; }; - 43C892991D9D6DD70022038D /* demux.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = demux.c; sourceTree = ""; }; 4A2CADFF1AB4BB5300B6BC39 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4A2CAE021AB4BB5400B6BC39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImage.h; sourceTree = ""; }; @@ -1662,117 +667,6 @@ 53FB894814D35E9E0020B787 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+ImageContentType.h"; sourceTree = ""; }; 5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+ImageContentType.m"; sourceTree = ""; }; - 80377BDE1F2F665300F89830 /* bit_reader_inl_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bit_reader_inl_utils.h; sourceTree = ""; }; - 80377BDF1F2F665300F89830 /* bit_reader_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bit_reader_utils.c; sourceTree = ""; }; - 80377BE01F2F665300F89830 /* bit_reader_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bit_reader_utils.h; sourceTree = ""; }; - 80377BE11F2F665300F89830 /* bit_writer_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bit_writer_utils.c; sourceTree = ""; }; - 80377BE21F2F665300F89830 /* bit_writer_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bit_writer_utils.h; sourceTree = ""; }; - 80377BE31F2F665300F89830 /* color_cache_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = color_cache_utils.c; sourceTree = ""; }; - 80377BE41F2F665300F89830 /* color_cache_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = color_cache_utils.h; sourceTree = ""; }; - 80377BE51F2F665300F89830 /* endian_inl_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endian_inl_utils.h; sourceTree = ""; }; - 80377BE61F2F665300F89830 /* filters_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filters_utils.c; sourceTree = ""; }; - 80377BE71F2F665300F89830 /* filters_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filters_utils.h; sourceTree = ""; }; - 80377BE81F2F665300F89830 /* huffman_encode_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = huffman_encode_utils.c; sourceTree = ""; }; - 80377BE91F2F665300F89830 /* huffman_encode_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = huffman_encode_utils.h; sourceTree = ""; }; - 80377BEA1F2F665300F89830 /* huffman_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = huffman_utils.c; sourceTree = ""; }; - 80377BEB1F2F665300F89830 /* huffman_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = huffman_utils.h; sourceTree = ""; }; - 80377BEC1F2F665300F89830 /* quant_levels_dec_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = quant_levels_dec_utils.c; sourceTree = ""; }; - 80377BED1F2F665300F89830 /* quant_levels_dec_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = quant_levels_dec_utils.h; sourceTree = ""; }; - 80377BEE1F2F665300F89830 /* quant_levels_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = quant_levels_utils.c; sourceTree = ""; }; - 80377BEF1F2F665300F89830 /* quant_levels_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = quant_levels_utils.h; sourceTree = ""; }; - 80377BF01F2F665300F89830 /* random_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = random_utils.c; sourceTree = ""; }; - 80377BF11F2F665300F89830 /* random_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = random_utils.h; sourceTree = ""; }; - 80377BF21F2F665300F89830 /* rescaler_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rescaler_utils.c; sourceTree = ""; }; - 80377BF31F2F665300F89830 /* rescaler_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rescaler_utils.h; sourceTree = ""; }; - 80377BF41F2F665300F89830 /* thread_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = thread_utils.c; sourceTree = ""; }; - 80377BF51F2F665300F89830 /* thread_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = thread_utils.h; sourceTree = ""; }; - 80377BF61F2F665300F89830 /* utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utils.c; sourceTree = ""; }; - 80377BF71F2F665300F89830 /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = ""; }; - 80377C941F2F66A100F89830 /* alpha_processing_mips_dsp_r2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alpha_processing_mips_dsp_r2.c; sourceTree = ""; }; - 80377C951F2F66A100F89830 /* alpha_processing_neon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alpha_processing_neon.c; sourceTree = ""; }; - 80377C961F2F66A100F89830 /* alpha_processing_sse2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alpha_processing_sse2.c; sourceTree = ""; }; - 80377C971F2F66A100F89830 /* alpha_processing_sse41.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alpha_processing_sse41.c; sourceTree = ""; }; - 80377C981F2F66A100F89830 /* alpha_processing.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alpha_processing.c; sourceTree = ""; }; - 80377C991F2F66A100F89830 /* argb_mips_dsp_r2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = argb_mips_dsp_r2.c; sourceTree = ""; }; - 80377C9A1F2F66A100F89830 /* argb_sse2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = argb_sse2.c; sourceTree = ""; }; - 80377C9B1F2F66A100F89830 /* argb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = argb.c; sourceTree = ""; }; - 80377C9C1F2F66A100F89830 /* common_sse2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common_sse2.h; sourceTree = ""; }; - 80377C9D1F2F66A100F89830 /* cost_mips_dsp_r2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cost_mips_dsp_r2.c; sourceTree = ""; }; - 80377C9E1F2F66A100F89830 /* cost_mips32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cost_mips32.c; sourceTree = ""; }; - 80377C9F1F2F66A100F89830 /* cost_sse2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cost_sse2.c; sourceTree = ""; }; - 80377CA01F2F66A100F89830 /* cost.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cost.c; sourceTree = ""; }; - 80377CA11F2F66A100F89830 /* cpu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpu.c; sourceTree = ""; }; - 80377CA21F2F66A100F89830 /* dec_clip_tables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dec_clip_tables.c; sourceTree = ""; }; - 80377CA31F2F66A100F89830 /* dec_mips_dsp_r2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dec_mips_dsp_r2.c; sourceTree = ""; }; - 80377CA41F2F66A100F89830 /* dec_mips32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dec_mips32.c; sourceTree = ""; }; - 80377CA51F2F66A100F89830 /* dec_msa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dec_msa.c; sourceTree = ""; }; - 80377CA61F2F66A100F89830 /* dec_neon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dec_neon.c; sourceTree = ""; }; - 80377CA71F2F66A100F89830 /* dec_sse2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dec_sse2.c; sourceTree = ""; }; - 80377CA81F2F66A100F89830 /* dec_sse41.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dec_sse41.c; sourceTree = ""; }; - 80377CA91F2F66A100F89830 /* dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dec.c; sourceTree = ""; }; - 80377CAA1F2F66A100F89830 /* dsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsp.h; sourceTree = ""; }; - 80377CAB1F2F66A100F89830 /* enc_avx2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = enc_avx2.c; sourceTree = ""; }; - 80377CAC1F2F66A100F89830 /* enc_mips_dsp_r2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = enc_mips_dsp_r2.c; sourceTree = ""; }; - 80377CAD1F2F66A100F89830 /* enc_mips32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = enc_mips32.c; sourceTree = ""; }; - 80377CAE1F2F66A100F89830 /* enc_msa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = enc_msa.c; sourceTree = ""; }; - 80377CAF1F2F66A100F89830 /* enc_neon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = enc_neon.c; sourceTree = ""; }; - 80377CB01F2F66A100F89830 /* enc_sse2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = enc_sse2.c; sourceTree = ""; }; - 80377CB11F2F66A100F89830 /* enc_sse41.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = enc_sse41.c; sourceTree = ""; }; - 80377CB21F2F66A100F89830 /* enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = enc.c; sourceTree = ""; }; - 80377CB31F2F66A100F89830 /* filters_mips_dsp_r2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filters_mips_dsp_r2.c; sourceTree = ""; }; - 80377CB41F2F66A100F89830 /* filters_msa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filters_msa.c; sourceTree = ""; }; - 80377CB51F2F66A100F89830 /* filters_neon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filters_neon.c; sourceTree = ""; }; - 80377CB61F2F66A100F89830 /* filters_sse2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filters_sse2.c; sourceTree = ""; }; - 80377CB71F2F66A100F89830 /* filters.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filters.c; sourceTree = ""; }; - 80377CB81F2F66A100F89830 /* lossless_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lossless_common.h; sourceTree = ""; }; - 80377CB91F2F66A100F89830 /* lossless_enc_mips_dsp_r2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lossless_enc_mips_dsp_r2.c; sourceTree = ""; }; - 80377CBA1F2F66A100F89830 /* lossless_enc_mips32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lossless_enc_mips32.c; sourceTree = ""; }; - 80377CBB1F2F66A100F89830 /* lossless_enc_msa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lossless_enc_msa.c; sourceTree = ""; }; - 80377CBC1F2F66A100F89830 /* lossless_enc_neon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lossless_enc_neon.c; sourceTree = ""; }; - 80377CBD1F2F66A100F89830 /* lossless_enc_sse2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lossless_enc_sse2.c; sourceTree = ""; }; - 80377CBE1F2F66A100F89830 /* lossless_enc_sse41.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lossless_enc_sse41.c; sourceTree = ""; }; - 80377CBF1F2F66A100F89830 /* lossless_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lossless_enc.c; sourceTree = ""; }; - 80377CC01F2F66A100F89830 /* lossless_mips_dsp_r2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lossless_mips_dsp_r2.c; sourceTree = ""; }; - 80377CC11F2F66A100F89830 /* lossless_msa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lossless_msa.c; sourceTree = ""; }; - 80377CC21F2F66A100F89830 /* lossless_neon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lossless_neon.c; sourceTree = ""; }; - 80377CC31F2F66A100F89830 /* lossless_sse2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lossless_sse2.c; sourceTree = ""; }; - 80377CC41F2F66A100F89830 /* lossless.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lossless.c; sourceTree = ""; }; - 80377CC51F2F66A100F89830 /* lossless.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lossless.h; sourceTree = ""; }; - 80377CC61F2F66A100F89830 /* mips_macro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mips_macro.h; sourceTree = ""; }; - 80377CC71F2F66A100F89830 /* msa_macro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = msa_macro.h; sourceTree = ""; }; - 80377CC81F2F66A100F89830 /* neon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = neon.h; sourceTree = ""; }; - 80377CC91F2F66A100F89830 /* rescaler_mips_dsp_r2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rescaler_mips_dsp_r2.c; sourceTree = ""; }; - 80377CCA1F2F66A100F89830 /* rescaler_mips32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rescaler_mips32.c; sourceTree = ""; }; - 80377CCB1F2F66A100F89830 /* rescaler_msa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rescaler_msa.c; sourceTree = ""; }; - 80377CCC1F2F66A100F89830 /* rescaler_neon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rescaler_neon.c; sourceTree = ""; }; - 80377CCD1F2F66A100F89830 /* rescaler_sse2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rescaler_sse2.c; sourceTree = ""; }; - 80377CCE1F2F66A100F89830 /* rescaler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rescaler.c; sourceTree = ""; }; - 80377CCF1F2F66A100F89830 /* upsampling_mips_dsp_r2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = upsampling_mips_dsp_r2.c; sourceTree = ""; }; - 80377CD01F2F66A100F89830 /* upsampling_msa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = upsampling_msa.c; sourceTree = ""; }; - 80377CD11F2F66A100F89830 /* upsampling_neon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = upsampling_neon.c; sourceTree = ""; }; - 80377CD21F2F66A100F89830 /* upsampling_sse2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = upsampling_sse2.c; sourceTree = ""; }; - 80377CD31F2F66A100F89830 /* upsampling.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = upsampling.c; sourceTree = ""; }; - 80377CD41F2F66A100F89830 /* yuv_mips_dsp_r2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yuv_mips_dsp_r2.c; sourceTree = ""; }; - 80377CD51F2F66A100F89830 /* yuv_mips32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yuv_mips32.c; sourceTree = ""; }; - 80377CD61F2F66A100F89830 /* yuv_sse2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yuv_sse2.c; sourceTree = ""; }; - 80377CD71F2F66A100F89830 /* yuv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yuv.c; sourceTree = ""; }; - 80377CD81F2F66A100F89830 /* yuv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = yuv.h; sourceTree = ""; }; - 80377E771F2F66D000F89830 /* alpha_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alpha_dec.c; sourceTree = ""; }; - 80377E781F2F66D000F89830 /* alphai_dec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alphai_dec.h; sourceTree = ""; }; - 80377E791F2F66D000F89830 /* buffer_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = buffer_dec.c; sourceTree = ""; }; - 80377E7A1F2F66D000F89830 /* common_dec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common_dec.h; sourceTree = ""; }; - 80377E7B1F2F66D000F89830 /* frame_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = frame_dec.c; sourceTree = ""; }; - 80377E7C1F2F66D000F89830 /* idec_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = idec_dec.c; sourceTree = ""; }; - 80377E7D1F2F66D000F89830 /* io_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = io_dec.c; sourceTree = ""; }; - 80377E7E1F2F66D000F89830 /* quant_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = quant_dec.c; sourceTree = ""; }; - 80377E7F1F2F66D000F89830 /* tree_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tree_dec.c; sourceTree = ""; }; - 80377E801F2F66D000F89830 /* vp8_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vp8_dec.c; sourceTree = ""; }; - 80377E811F2F66D000F89830 /* vp8_dec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vp8_dec.h; sourceTree = ""; }; - 80377E821F2F66D000F89830 /* vp8i_dec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vp8i_dec.h; sourceTree = ""; }; - 80377E831F2F66D000F89830 /* vp8l_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vp8l_dec.c; sourceTree = ""; }; - 80377E841F2F66D000F89830 /* vp8li_dec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vp8li_dec.h; sourceTree = ""; }; - 80377E851F2F66D000F89830 /* webp_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = webp_dec.c; sourceTree = ""; }; - 80377E861F2F66D000F89830 /* webpi_dec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = webpi_dec.h; sourceTree = ""; }; 807A12261F89636300EC2A9B /* SDImageCodersManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageCodersManager.h; sourceTree = ""; }; 807A12271F89636300EC2A9B /* SDImageCodersManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageCodersManager.m; sourceTree = ""; }; A18A6CC5172DC28500419892 /* UIImage+GIF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+GIF.h"; sourceTree = ""; }; @@ -1781,13 +675,6 @@ AB615302192DA24600A2D8E9 /* UIView+WebCacheOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+WebCacheOperation.m"; sourceTree = ""; }; ABBE71A518C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImageView+HighlightedWebCache.h"; path = "SDWebImage/UIImageView+HighlightedWebCache.h"; sourceTree = ""; }; ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+HighlightedWebCache.m"; path = "SDWebImage/UIImageView+HighlightedWebCache.m"; sourceTree = ""; }; - DA577CC41998E60B007367ED /* decode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = decode.h; sourceTree = ""; }; - DA577CC51998E60B007367ED /* demux.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = demux.h; sourceTree = ""; }; - DA577CC61998E60B007367ED /* encode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = encode.h; sourceTree = ""; }; - DA577CC71998E60B007367ED /* format_constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = format_constants.h; sourceTree = ""; }; - DA577CC81998E60B007367ED /* mux.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mux.h; sourceTree = ""; }; - DA577CC91998E60B007367ED /* mux_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mux_types.h; sourceTree = ""; }; - DA577CCA1998E60B007367ED /* types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = types.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1863,55 +750,6 @@ name = Decoder; sourceTree = ""; }; - 323F8B121F38EF770092B609 /* enc */ = { - isa = PBXGroup; - children = ( - 323F8B131F38EF770092B609 /* alpha_enc.c */, - 323F8B141F38EF770092B609 /* analysis_enc.c */, - 323F8B151F38EF770092B609 /* backward_references_enc.c */, - 323F8B161F38EF770092B609 /* backward_references_enc.h */, - 323F8B171F38EF770092B609 /* config_enc.c */, - 323F8B181F38EF770092B609 /* cost_enc.c */, - 323F8B191F38EF770092B609 /* cost_enc.h */, - 323F8B1A1F38EF770092B609 /* delta_palettization_enc.c */, - 323F8B1B1F38EF770092B609 /* delta_palettization_enc.h */, - 323F8B1C1F38EF770092B609 /* filter_enc.c */, - 323F8B1D1F38EF770092B609 /* frame_enc.c */, - 323F8B1E1F38EF770092B609 /* histogram_enc.c */, - 323F8B1F1F38EF770092B609 /* histogram_enc.h */, - 323F8B201F38EF770092B609 /* iterator_enc.c */, - 323F8B221F38EF770092B609 /* near_lossless_enc.c */, - 323F8B231F38EF770092B609 /* picture_csp_enc.c */, - 323F8B241F38EF770092B609 /* picture_enc.c */, - 323F8B251F38EF770092B609 /* picture_psnr_enc.c */, - 323F8B261F38EF770092B609 /* picture_rescale_enc.c */, - 323F8B271F38EF770092B609 /* picture_tools_enc.c */, - 323F8B281F38EF770092B609 /* predictor_enc.c */, - 323F8B291F38EF770092B609 /* quant_enc.c */, - 323F8B2A1F38EF770092B609 /* syntax_enc.c */, - 323F8B2B1F38EF770092B609 /* token_enc.c */, - 323F8B2C1F38EF770092B609 /* tree_enc.c */, - 323F8B2D1F38EF770092B609 /* vp8i_enc.h */, - 323F8B2E1F38EF770092B609 /* vp8l_enc.c */, - 323F8B2F1F38EF770092B609 /* vp8li_enc.h */, - 323F8B301F38EF770092B609 /* webp_enc.c */, - ); - path = enc; - sourceTree = ""; - }; - 323F8B311F38EF770092B609 /* mux */ = { - isa = PBXGroup; - children = ( - 323F8B321F38EF770092B609 /* anim_encode.c */, - 323F8B331F38EF770092B609 /* animi.h */, - 323F8B3A1F38EF770092B609 /* muxedit.c */, - 323F8B3B1F38EF770092B609 /* muxi.h */, - 323F8B3C1F38EF770092B609 /* muxinternal.c */, - 323F8B3D1F38EF770092B609 /* muxread.c */, - ); - path = mux; - sourceTree = ""; - }; 32484756201775CE00AF9E5A /* ImageView */ = { isa = PBXGroup; children = ( @@ -1967,17 +805,6 @@ path = MapKit; sourceTree = ""; }; - 32FDE88420888726008D7530 /* WebP */ = { - isa = PBXGroup; - children = ( - 32FDE88720888726008D7530 /* UIImage+WebP.h */, - 32FDE88520888726008D7530 /* UIImage+WebP.m */, - 32FDE88620888726008D7530 /* SDImageWebPCoder.h */, - 32FDE88820888726008D7530 /* SDImageWebPCoder.m */, - ); - path = WebP; - sourceTree = ""; - }; 4369C2851D9811BB007E863A /* WebCache Categories */ = { isa = PBXGroup; children = ( @@ -1996,15 +823,6 @@ path = ..; sourceTree = ""; }; - 43C892971D9D6DBB0022038D /* demux */ = { - isa = PBXGroup; - children = ( - 43C892981D9D6DD70022038D /* anim_decode.c */, - 43C892991D9D6DD70022038D /* demux.c */, - ); - path = demux; - sourceTree = ""; - }; 4A2CAE001AB4BB5300B6BC39 /* WebImage */ = { isa = PBXGroup; children = ( @@ -2050,7 +868,6 @@ 53922D71148C55820056699D /* Frameworks */ = { isa = PBXGroup; children = ( - DA577C121998E60B007367ED /* libwebp */, 53FB893F14D35D1A0020B787 /* CoreGraphics.framework */, 53922D72148C55820056699D /* Foundation.framework */, 53FB894814D35E9E0020B787 /* UIKit.framework */, @@ -2072,7 +889,6 @@ 53922DA9148C562D0056699D /* Categories */, 4369C2851D9811BB007E863A /* WebCache Categories */, 32FDE8792088871B008D7530 /* MapKit */, - 32FDE88420888726008D7530 /* WebP */, ); path = SDWebImage; sourceTree = ""; @@ -2156,175 +972,6 @@ name = Utils; sourceTree = ""; }; - DA577C121998E60B007367ED /* libwebp */ = { - isa = PBXGroup; - children = ( - DA577C4F1998E60B007367ED /* src */, - ); - name = libwebp; - path = Vendors/libwebp; - sourceTree = ""; - }; - DA577C4F1998E60B007367ED /* src */ = { - isa = PBXGroup; - children = ( - DA577D5A1998E6B2007367ED /* dec */, - 43C892971D9D6DBB0022038D /* demux */, - DA577C651998E60B007367ED /* dsp */, - 323F8B121F38EF770092B609 /* enc */, - 323F8B311F38EF770092B609 /* mux */, - DA577CA71998E60B007367ED /* utils */, - DA577CC31998E60B007367ED /* webp */, - ); - path = src; - sourceTree = ""; - }; - DA577C651998E60B007367ED /* dsp */ = { - isa = PBXGroup; - children = ( - 80377C941F2F66A100F89830 /* alpha_processing_mips_dsp_r2.c */, - 80377C951F2F66A100F89830 /* alpha_processing_neon.c */, - 80377C961F2F66A100F89830 /* alpha_processing_sse2.c */, - 80377C971F2F66A100F89830 /* alpha_processing_sse41.c */, - 80377C981F2F66A100F89830 /* alpha_processing.c */, - 80377C991F2F66A100F89830 /* argb_mips_dsp_r2.c */, - 80377C9A1F2F66A100F89830 /* argb_sse2.c */, - 80377C9B1F2F66A100F89830 /* argb.c */, - 80377C9C1F2F66A100F89830 /* common_sse2.h */, - 80377C9D1F2F66A100F89830 /* cost_mips_dsp_r2.c */, - 80377C9E1F2F66A100F89830 /* cost_mips32.c */, - 80377C9F1F2F66A100F89830 /* cost_sse2.c */, - 80377CA01F2F66A100F89830 /* cost.c */, - 80377CA11F2F66A100F89830 /* cpu.c */, - 80377CA21F2F66A100F89830 /* dec_clip_tables.c */, - 80377CA31F2F66A100F89830 /* dec_mips_dsp_r2.c */, - 80377CA41F2F66A100F89830 /* dec_mips32.c */, - 80377CA51F2F66A100F89830 /* dec_msa.c */, - 80377CA61F2F66A100F89830 /* dec_neon.c */, - 80377CA71F2F66A100F89830 /* dec_sse2.c */, - 80377CA81F2F66A100F89830 /* dec_sse41.c */, - 80377CA91F2F66A100F89830 /* dec.c */, - 80377CAA1F2F66A100F89830 /* dsp.h */, - 80377CAB1F2F66A100F89830 /* enc_avx2.c */, - 80377CAC1F2F66A100F89830 /* enc_mips_dsp_r2.c */, - 80377CAD1F2F66A100F89830 /* enc_mips32.c */, - 80377CAE1F2F66A100F89830 /* enc_msa.c */, - 80377CAF1F2F66A100F89830 /* enc_neon.c */, - 80377CB01F2F66A100F89830 /* enc_sse2.c */, - 80377CB11F2F66A100F89830 /* enc_sse41.c */, - 80377CB21F2F66A100F89830 /* enc.c */, - 80377CB31F2F66A100F89830 /* filters_mips_dsp_r2.c */, - 80377CB41F2F66A100F89830 /* filters_msa.c */, - 80377CB51F2F66A100F89830 /* filters_neon.c */, - 80377CB61F2F66A100F89830 /* filters_sse2.c */, - 80377CB71F2F66A100F89830 /* filters.c */, - 80377CB81F2F66A100F89830 /* lossless_common.h */, - 80377CB91F2F66A100F89830 /* lossless_enc_mips_dsp_r2.c */, - 80377CBA1F2F66A100F89830 /* lossless_enc_mips32.c */, - 80377CBB1F2F66A100F89830 /* lossless_enc_msa.c */, - 80377CBC1F2F66A100F89830 /* lossless_enc_neon.c */, - 80377CBD1F2F66A100F89830 /* lossless_enc_sse2.c */, - 80377CBE1F2F66A100F89830 /* lossless_enc_sse41.c */, - 80377CBF1F2F66A100F89830 /* lossless_enc.c */, - 80377CC01F2F66A100F89830 /* lossless_mips_dsp_r2.c */, - 80377CC11F2F66A100F89830 /* lossless_msa.c */, - 80377CC21F2F66A100F89830 /* lossless_neon.c */, - 80377CC31F2F66A100F89830 /* lossless_sse2.c */, - 80377CC41F2F66A100F89830 /* lossless.c */, - 80377CC51F2F66A100F89830 /* lossless.h */, - 80377CC61F2F66A100F89830 /* mips_macro.h */, - 80377CC71F2F66A100F89830 /* msa_macro.h */, - 80377CC81F2F66A100F89830 /* neon.h */, - 80377CC91F2F66A100F89830 /* rescaler_mips_dsp_r2.c */, - 80377CCA1F2F66A100F89830 /* rescaler_mips32.c */, - 80377CCB1F2F66A100F89830 /* rescaler_msa.c */, - 80377CCC1F2F66A100F89830 /* rescaler_neon.c */, - 80377CCD1F2F66A100F89830 /* rescaler_sse2.c */, - 80377CCE1F2F66A100F89830 /* rescaler.c */, - 80377CCF1F2F66A100F89830 /* upsampling_mips_dsp_r2.c */, - 80377CD01F2F66A100F89830 /* upsampling_msa.c */, - 80377CD11F2F66A100F89830 /* upsampling_neon.c */, - 80377CD21F2F66A100F89830 /* upsampling_sse2.c */, - 80377CD31F2F66A100F89830 /* upsampling.c */, - 80377CD41F2F66A100F89830 /* yuv_mips_dsp_r2.c */, - 80377CD51F2F66A100F89830 /* yuv_mips32.c */, - 80377CD61F2F66A100F89830 /* yuv_sse2.c */, - 80377CD71F2F66A100F89830 /* yuv.c */, - 80377CD81F2F66A100F89830 /* yuv.h */, - ); - path = dsp; - sourceTree = ""; - }; - DA577CA71998E60B007367ED /* utils */ = { - isa = PBXGroup; - children = ( - 80377BDE1F2F665300F89830 /* bit_reader_inl_utils.h */, - 80377BDF1F2F665300F89830 /* bit_reader_utils.c */, - 80377BE01F2F665300F89830 /* bit_reader_utils.h */, - 80377BE11F2F665300F89830 /* bit_writer_utils.c */, - 80377BE21F2F665300F89830 /* bit_writer_utils.h */, - 80377BE31F2F665300F89830 /* color_cache_utils.c */, - 80377BE41F2F665300F89830 /* color_cache_utils.h */, - 80377BE51F2F665300F89830 /* endian_inl_utils.h */, - 80377BE61F2F665300F89830 /* filters_utils.c */, - 80377BE71F2F665300F89830 /* filters_utils.h */, - 80377BE81F2F665300F89830 /* huffman_encode_utils.c */, - 80377BE91F2F665300F89830 /* huffman_encode_utils.h */, - 80377BEA1F2F665300F89830 /* huffman_utils.c */, - 80377BEB1F2F665300F89830 /* huffman_utils.h */, - 80377BEC1F2F665300F89830 /* quant_levels_dec_utils.c */, - 80377BED1F2F665300F89830 /* quant_levels_dec_utils.h */, - 80377BEE1F2F665300F89830 /* quant_levels_utils.c */, - 80377BEF1F2F665300F89830 /* quant_levels_utils.h */, - 80377BF01F2F665300F89830 /* random_utils.c */, - 80377BF11F2F665300F89830 /* random_utils.h */, - 80377BF21F2F665300F89830 /* rescaler_utils.c */, - 80377BF31F2F665300F89830 /* rescaler_utils.h */, - 80377BF41F2F665300F89830 /* thread_utils.c */, - 80377BF51F2F665300F89830 /* thread_utils.h */, - 80377BF61F2F665300F89830 /* utils.c */, - 80377BF71F2F665300F89830 /* utils.h */, - ); - path = utils; - sourceTree = ""; - }; - DA577CC31998E60B007367ED /* webp */ = { - isa = PBXGroup; - children = ( - DA577CC41998E60B007367ED /* decode.h */, - DA577CC51998E60B007367ED /* demux.h */, - DA577CC61998E60B007367ED /* encode.h */, - DA577CC71998E60B007367ED /* format_constants.h */, - DA577CC81998E60B007367ED /* mux.h */, - DA577CC91998E60B007367ED /* mux_types.h */, - DA577CCA1998E60B007367ED /* types.h */, - ); - path = webp; - sourceTree = ""; - }; - DA577D5A1998E6B2007367ED /* dec */ = { - isa = PBXGroup; - children = ( - 80377E771F2F66D000F89830 /* alpha_dec.c */, - 80377E781F2F66D000F89830 /* alphai_dec.h */, - 80377E791F2F66D000F89830 /* buffer_dec.c */, - 80377E7A1F2F66D000F89830 /* common_dec.h */, - 80377E7B1F2F66D000F89830 /* frame_dec.c */, - 80377E7C1F2F66D000F89830 /* idec_dec.c */, - 80377E7D1F2F66D000F89830 /* io_dec.c */, - 80377E7E1F2F66D000F89830 /* quant_dec.c */, - 80377E7F1F2F66D000F89830 /* tree_dec.c */, - 80377E801F2F66D000F89830 /* vp8_dec.c */, - 80377E811F2F66D000F89830 /* vp8_dec.h */, - 80377E821F2F66D000F89830 /* vp8i_dec.h */, - 80377E831F2F66D000F89830 /* vp8l_dec.c */, - 80377E841F2F66D000F89830 /* vp8li_dec.h */, - 80377E851F2F66D000F89830 /* webp_dec.c */, - 80377E861F2F66D000F89830 /* webpi_dec.h */, - ); - path = dec; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -2332,95 +979,50 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 80377DDC1F2F66A700F89830 /* neon.h in Headers */, - 80377DEC1F2F66A700F89830 /* yuv.h in Headers */, - 80377DDA1F2F66A700F89830 /* mips_macro.h in Headers */, - 80377C571F2F666300F89830 /* quant_levels_utils.h in Headers */, - 323F8B531F38EF770092B609 /* backward_references_enc.h in Headers */, - 4317395A1CDFC8B70008FEB9 /* mux_types.h in Headers */, - 431739561CDFC8B70008FEB9 /* demux.h in Headers */, 32D122212080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 32B9B53A206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AD2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, - 80377C4A1F2F666300F89830 /* bit_writer_utils.h in Headers */, 321B37902083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, - 323F8BE71F38EF770092B609 /* vp8li_enc.h in Headers */, 329A185C1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, 4369C27A1D9807EC007E863A /* UIView+WebCache.h in Headers */, 32F21B5420788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, - 80377DCC1F2F66A700F89830 /* lossless_common.h in Headers */, 321E60971F38E8ED00405457 /* SDImageIOCoder.h in Headers */, 43A918671D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 327054D7206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, - 431739571CDFC8B70008FEB9 /* encode.h in Headers */, - 323F8B711F38EF770092B609 /* delta_palettization_enc.h in Headers */, 3290FA071FA478AF0047D20C /* SDImageFrame.h in Headers */, 324DF4B7200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 807A122B1F89636300EC2A9B /* SDImageCodersManager.h in Headers */, - 80377EC61F2F66D500F89830 /* webpi_dec.h in Headers */, - 80377C591F2F666300F89830 /* random_utils.h in Headers */, - 80377DD91F2F66A700F89830 /* lossless.h in Headers */, 00733A681BC4880E00A5A117 /* SDWebImageManager.h in Headers */, - 431739591CDFC8B70008FEB9 /* mux.h in Headers */, 00733A6C1BC4880E00A5A117 /* UIButton+WebCache.h in Headers */, - 80377DB01F2F66A700F89830 /* common_sse2.h in Headers */, 320CAE182086F50500CFFC80 /* SDWebImageError.h in Headers */, - 80377DDB1F2F66A700F89830 /* msa_macro.h in Headers */, - 4317395B1CDFC8B70008FEB9 /* types.h in Headers */, - 80377C531F2F666300F89830 /* huffman_utils.h in Headers */, 32FDE8822088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, - 431739551CDFC8B70008FEB9 /* decode.h in Headers */, 00733A731BC4880E00A5A117 /* SDWebImage.h in Headers */, - 323F8B651F38EF770092B609 /* cost_enc.h in Headers */, 328BB6C42082581100760D6C /* SDDiskCache.h in Headers */, 00733A701BC4880E00A5A117 /* UIImageView+HighlightedWebCache.h in Headers */, - 323F8BDB1F38EF770092B609 /* vp8i_enc.h in Headers */, - 80377C461F2F666300F89830 /* bit_reader_inl_utils.h in Headers */, - 32FDE89220888726008D7530 /* SDImageWebPCoder.h in Headers */, 00733A671BC4880E00A5A117 /* SDImageCache.h in Headers */, 00733A711BC4880E00A5A117 /* UIImageView+WebCache.h in Headers */, 00733A631BC4880E00A5A117 /* SDWebImageCompat.h in Headers */, 00733A661BC4880E00A5A117 /* SDWebImageDownloaderOperation.h in Headers */, - 80377C5D1F2F666300F89830 /* thread_utils.h in Headers */, 328BB6D02082581100760D6C /* SDMemoryCache.h in Headers */, 321E60891F38E8C800405457 /* SDImageCoder.h in Headers */, 00733A721BC4880E00A5A117 /* UIView+WebCacheOperation.h in Headers */, 321B37842083290E00C0EA77 /* SDImageLoader.h in Headers */, - 80377C481F2F666300F89830 /* bit_reader_utils.h in Headers */, - 80377C511F2F666300F89830 /* huffman_encode_utils.h in Headers */, 32484778201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 00733A6B1BC4880E00A5A117 /* NSData+ImageContentType.h in Headers */, 325312CB200F09910046BF1E /* SDWebImageTransition.h in Headers */, - 323F8C111F38EF770092B609 /* muxi.h in Headers */, - 80377EC41F2F66D500F89830 /* vp8li_dec.h in Headers */, 00733A6A1BC4880E00A5A117 /* SDWebImagePrefetcher.h in Headers */, 00733A641BC4880E00A5A117 /* SDWebImageOperation.h in Headers */, 32484766201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 321E60A51F38E8F600405457 /* SDImageGIFCoder.h in Headers */, 32CF1C0A1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, - 80377C4D1F2F666300F89830 /* endian_inl_utils.h in Headers */, - 431739581CDFC8B70008FEB9 /* format_constants.h in Headers */, 00733A6E1BC4880E00A5A117 /* UIImage+MultiFormat.h in Headers */, - 323F8B891F38EF770092B609 /* histogram_enc.h in Headers */, - 80377EC21F2F66D500F89830 /* vp8i_dec.h in Headers */, - 80377EBA1F2F66D500F89830 /* common_dec.h in Headers */, 3248476C201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, - 32FDE89820888726008D7530 /* UIImage+WebP.h in Headers */, - 80377C5F1F2F666300F89830 /* utils.h in Headers */, - 80377C5B1F2F666300F89830 /* rescaler_utils.h in Headers */, 32D122332080B2EB003685A3 /* SDImageCachesManager.h in Headers */, - 323F8BF91F38EF770092B609 /* animi.h in Headers */, 32F7C0872030719600873181 /* UIImage+Transform.h in Headers */, - 80377C4F1F2F666300F89830 /* filters_utils.h in Headers */, - 80377C4C1F2F666300F89830 /* color_cache_utils.h in Headers */, 32C0FDE42013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 321E60C11F38E91700405457 /* UIImage+ForceDecode.h in Headers */, - 80377DBE1F2F66A700F89830 /* dsp.h in Headers */, 32F7C0722030114C00873181 /* SDImageTransformer.h in Headers */, - 80377EB81F2F66D400F89830 /* alphai_dec.h in Headers */, 00733A6D1BC4880E00A5A117 /* UIImage+GIF.h in Headers */, - 80377C551F2F666300F89830 /* quant_levels_dec_utils.h in Headers */, - 80377EC11F2F66D500F89830 /* vp8_dec.h in Headers */, 00733A651BC4880E00A5A117 /* SDWebImageDownloader.h in Headers */, 328BB69F2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, ); @@ -2430,96 +1032,51 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 80377D521F2F66A700F89830 /* neon.h in Headers */, - 80377D261F2F66A700F89830 /* common_sse2.h in Headers */, 3290FA051FA478AF0047D20C /* SDImageFrame.h in Headers */, - 80377C1D1F2F666300F89830 /* huffman_encode_utils.h in Headers */, - 80377E9A1F2F66D400F89830 /* common_dec.h in Headers */, 32D1221F2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 327054D5206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, 328BB6AB2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 32B9B538206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, - 80377C231F2F666300F89830 /* quant_levels_utils.h in Headers */, 321E60BF1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, - 80377EA61F2F66D400F89830 /* webpi_dec.h in Headers */, 807A12291F89636300EC2A9B /* SDImageCodersManager.h in Headers */, 32F7C0852030719600873181 /* UIImage+Transform.h in Headers */, - 32FDE89020888726008D7530 /* SDImageWebPCoder.h in Headers */, - 80377C141F2F666300F89830 /* bit_reader_utils.h in Headers */, 328BB69D2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, - 323F8C0F1F38EF770092B609 /* muxi.h in Headers */, 32F7C0702030114C00873181 /* SDImageTransformer.h in Headers */, - 80377C2B1F2F666300F89830 /* utils.h in Headers */, - 4314D1621D0E0E3B004B36C9 /* mux_types.h in Headers */, - 4314D1631D0E0E3B004B36C9 /* demux.h in Headers */, - 80377D421F2F66A700F89830 /* lossless_common.h in Headers */, 32CF1C081FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, - 4314D16B1D0E0E3B004B36C9 /* encode.h in Headers */, - 80377D501F2F66A700F89830 /* mips_macro.h in Headers */, - 80377C291F2F666300F89830 /* thread_utils.h in Headers */, 4314D16D1D0E0E3B004B36C9 /* SDImageCache.h in Headers */, 329A185A1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, 4314D16F1D0E0E3B004B36C9 /* NSData+ImageContentType.h in Headers */, - 80377C121F2F666300F89830 /* bit_reader_inl_utils.h in Headers */, - 4314D1701D0E0E3B004B36C9 /* mux.h in Headers */, 321B378E2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, 321E60871F38E8C800405457 /* SDImageCoder.h in Headers */, - 80377EA21F2F66D400F89830 /* vp8i_dec.h in Headers */, 320CAE162086F50500CFFC80 /* SDWebImageError.h in Headers */, 3248476A201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 321E60951F38E8ED00405457 /* SDImageIOCoder.h in Headers */, - 80377C211F2F666300F89830 /* quant_levels_dec_utils.h in Headers */, 4314D1721D0E0E3B004B36C9 /* SDWebImageCompat.h in Headers */, 32484776201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 321B37822083290E00C0EA77 /* SDImageLoader.h in Headers */, - 80377C251F2F666300F89830 /* random_utils.h in Headers */, - 80377D4F1F2F66A700F89830 /* lossless.h in Headers */, - 80377D511F2F66A700F89830 /* msa_macro.h in Headers */, - 323F8BD91F38EF770092B609 /* vp8i_enc.h in Headers */, - 80377EA11F2F66D400F89830 /* vp8_dec.h in Headers */, - 80377C271F2F666300F89830 /* rescaler_utils.h in Headers */, - 323F8B511F38EF770092B609 /* backward_references_enc.h in Headers */, 325312C9200F09910046BF1E /* SDWebImageTransition.h in Headers */, 32D122312080B2EB003685A3 /* SDImageCachesManager.h in Headers */, 43A918651D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, - 4314D1741D0E0E3B004B36C9 /* types.h in Headers */, - 4314D1761D0E0E3B004B36C9 /* decode.h in Headers */, - 80377C1B1F2F666300F89830 /* filters_utils.h in Headers */, - 323F8B6F1F38EF770092B609 /* delta_palettization_enc.h in Headers */, 4314D1781D0E0E3B004B36C9 /* SDWebImageDownloader.h in Headers */, 32C0FDE22013426C001B8F2D /* SDWebImageIndicator.h in Headers */, - 80377E981F2F66D400F89830 /* alphai_dec.h in Headers */, 4314D1791D0E0E3B004B36C9 /* SDWebImageManager.h in Headers */, - 323F8BE51F38EF770092B609 /* vp8li_enc.h in Headers */, 324DF4B5200A14DC008A84CC /* SDWebImageDefine.h in Headers */, - 80377C191F2F666300F89830 /* endian_inl_utils.h in Headers */, 321E60A31F38E8F600405457 /* SDImageGIFCoder.h in Headers */, 32FDE8A320888789008D7530 /* SDWebImage.h in Headers */, 32F21B5220788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 4369C2781D9807EC007E863A /* UIView+WebCache.h in Headers */, - 80377D621F2F66A700F89830 /* yuv.h in Headers */, - 32FDE89620888726008D7530 /* UIImage+WebP.h in Headers */, - 80377D341F2F66A700F89830 /* dsp.h in Headers */, 4314D17D1D0E0E3B004B36C9 /* SDWebImagePrefetcher.h in Headers */, - 80377C181F2F666300F89830 /* color_cache_utils.h in Headers */, - 323F8B871F38EF770092B609 /* histogram_enc.h in Headers */, 328BB6CE2082581100760D6C /* SDMemoryCache.h in Headers */, - 80377C1F1F2F666300F89830 /* huffman_utils.h in Headers */, 4314D17F1D0E0E3B004B36C9 /* UIButton+WebCache.h in Headers */, 32484764201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 4314D1811D0E0E3B004B36C9 /* UIImageView+WebCache.h in Headers */, 4314D1841D0E0E3B004B36C9 /* SDWebImageOperation.h in Headers */, 4314D1851D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.h in Headers */, 4314D1861D0E0E3B004B36C9 /* UIImageView+HighlightedWebCache.h in Headers */, - 4314D1881D0E0E3B004B36C9 /* format_constants.h in Headers */, 328BB6C22082581100760D6C /* SDDiskCache.h in Headers */, - 323F8B631F38EF770092B609 /* cost_enc.h in Headers */, - 323F8BF71F38EF770092B609 /* animi.h in Headers */, 4314D18F1D0E0E3B004B36C9 /* UIView+WebCacheOperation.h in Headers */, 4314D1901D0E0E3B004B36C9 /* UIImage+GIF.h in Headers */, - 80377C161F2F666300F89830 /* bit_writer_utils.h in Headers */, 4314D1921D0E0E3B004B36C9 /* UIImage+MultiFormat.h in Headers */, - 80377EA41F2F66D400F89830 /* vp8li_dec.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2528,92 +1085,47 @@ buildActionMask = 2147483647; files = ( 321B37912083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, - 80377C791F2F666400F89830 /* utils.h in Headers */, 328BB6A02081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, - 323F8B721F38EF770092B609 /* delta_palettization_enc.h in Headers */, 32CF1C0B1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, 431BB6D91D06D2C1006A3455 /* SDWebImageManager.h in Headers */, - 80377C691F2F666400F89830 /* filters_utils.h in Headers */, - 80377EC81F2F66D500F89830 /* alphai_dec.h in Headers */, - 43A62A1B1D0E0A800089D7DD /* decode.h in Headers */, 321E608A1F38E8C800405457 /* SDImageCoder.h in Headers */, 32484767201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, - 80377C601F2F666400F89830 /* bit_reader_inl_utils.h in Headers */, - 32FDE89920888726008D7530 /* UIImage+WebP.h in Headers */, 321B37852083290E00C0EA77 /* SDImageLoader.h in Headers */, 329A185D1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, 431BB6DC1D06D2C1006A3455 /* UIButton+WebCache.h in Headers */, 431BB6E11D06D2C1006A3455 /* SDWebImage.h in Headers */, - 80377E311F2F66A800F89830 /* yuv.h in Headers */, - 80377ECA1F2F66D500F89830 /* common_dec.h in Headers */, - 80377C771F2F666400F89830 /* thread_utils.h in Headers */, - 80377E1F1F2F66A800F89830 /* mips_macro.h in Headers */, - 323F8B661F38EF770092B609 /* cost_enc.h in Headers */, - 80377C621F2F666400F89830 /* bit_reader_utils.h in Headers */, 431BB6E21D06D2C1006A3455 /* UIImageView+HighlightedWebCache.h in Headers */, - 43A62A1C1D0E0A800089D7DD /* demux.h in Headers */, 321E60C21F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 431BB6E31D06D2C1006A3455 /* SDImageCache.h in Headers */, - 43A62A1D1D0E0A800089D7DD /* encode.h in Headers */, 431BB6E61D06D2C1006A3455 /* UIImageView+WebCache.h in Headers */, - 80377E201F2F66A800F89830 /* msa_macro.h in Headers */, - 80377E031F2F66A800F89830 /* dsp.h in Headers */, - 80377C661F2F666400F89830 /* color_cache_utils.h in Headers */, 3290FA081FA478AF0047D20C /* SDImageFrame.h in Headers */, 321E60A61F38E8F600405457 /* SDImageGIFCoder.h in Headers */, 431BB6E71D06D2C1006A3455 /* SDWebImageCompat.h in Headers */, - 80377E211F2F66A800F89830 /* neon.h in Headers */, - 80377C711F2F666400F89830 /* quant_levels_utils.h in Headers */, - 323F8B541F38EF770092B609 /* backward_references_enc.h in Headers */, 32D122342080B2EB003685A3 /* SDImageCachesManager.h in Headers */, 32F7C0882030719600873181 /* UIImage+Transform.h in Headers */, - 43A62A1F1D0E0A800089D7DD /* mux.h in Headers */, 431BB6E91D06D2C1006A3455 /* SDWebImageDownloaderOperation.h in Headers */, - 80377ED41F2F66D500F89830 /* vp8li_dec.h in Headers */, 431BB6EB1D06D2C1006A3455 /* UIView+WebCacheOperation.h in Headers */, 325312CC200F09910046BF1E /* SDWebImageTransition.h in Headers */, - 80377C6D1F2F666400F89830 /* huffman_utils.h in Headers */, - 80377C731F2F666400F89830 /* random_utils.h in Headers */, 328BB6C52082581100760D6C /* SDDiskCache.h in Headers */, 431BB6EE1D06D2C1006A3455 /* NSData+ImageContentType.h in Headers */, 431BB6EF1D06D2C1006A3455 /* SDWebImagePrefetcher.h in Headers */, - 80377C671F2F666400F89830 /* endian_inl_utils.h in Headers */, 328BB6AE2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, - 80377C6B1F2F666400F89830 /* huffman_encode_utils.h in Headers */, - 323F8C121F38EF770092B609 /* muxi.h in Headers */, 32C0FDE52013426C001B8F2D /* SDWebImageIndicator.h in Headers */, - 80377ED61F2F66D500F89830 /* webpi_dec.h in Headers */, - 323F8BE81F38EF770092B609 /* vp8li_enc.h in Headers */, - 32FDE89320888726008D7530 /* SDImageWebPCoder.h in Headers */, - 323F8B8A1F38EF770092B609 /* histogram_enc.h in Headers */, - 80377E1E1F2F66A800F89830 /* lossless.h in Headers */, 321E60981F38E8ED00405457 /* SDImageIOCoder.h in Headers */, 328BB6D12082581100760D6C /* SDMemoryCache.h in Headers */, 4369C27B1D9807EC007E863A /* UIView+WebCache.h in Headers */, - 80377ED11F2F66D500F89830 /* vp8_dec.h in Headers */, 324DF4B8200A14DC008A84CC /* SDWebImageDefine.h in Headers */, - 80377C751F2F666400F89830 /* rescaler_utils.h in Headers */, - 80377C6F1F2F666400F89830 /* quant_levels_dec_utils.h in Headers */, 431BB6F01D06D2C1006A3455 /* SDWebImageOperation.h in Headers */, - 43A62A201D0E0A800089D7DD /* mux_types.h in Headers */, - 43A62A211D0E0A800089D7DD /* types.h in Headers */, - 80377C641F2F666400F89830 /* bit_writer_utils.h in Headers */, 32B9B53B206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, - 43A62A1E1D0E0A800089D7DD /* format_constants.h in Headers */, - 80377E111F2F66A800F89830 /* lossless_common.h in Headers */, 431BB6F61D06D2C1006A3455 /* UIImage+MultiFormat.h in Headers */, 320CAE192086F50500CFFC80 /* SDWebImageError.h in Headers */, 32F21B5520788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 807A122C1F89636300EC2A9B /* SDImageCodersManager.h in Headers */, - 323F8BFA1F38EF770092B609 /* animi.h in Headers */, 431BB6F91D06D2C1006A3455 /* UIImage+GIF.h in Headers */, 32F7C0732030114C00873181 /* SDImageTransformer.h in Headers */, 431BB6FA1D06D2C1006A3455 /* SDWebImageDownloader.h in Headers */, 3248476D201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 32D122222080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, - 80377DF51F2F66A800F89830 /* common_sse2.h in Headers */, - 323F8BDC1F38EF770092B609 /* vp8i_enc.h in Headers */, - 80377ED21F2F66D500F89830 /* vp8i_dec.h in Headers */, 32484779201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 327054D8206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, 43A918681D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, @@ -2624,99 +1136,54 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 80377C7E1F2F666400F89830 /* bit_writer_utils.h in Headers */, - 80377ED81F2F66D500F89830 /* alphai_dec.h in Headers */, 321E60A71F38E8F600405457 /* SDImageGIFCoder.h in Headers */, 324DF4B9200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 32F7C0892030719600873181 /* UIImage+Transform.h in Headers */, - 80377EDA1F2F66D500F89830 /* common_dec.h in Headers */, - 80377EE61F2F66D500F89830 /* webpi_dec.h in Headers */, 32D122232080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 32B9B53C206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AF2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, - 4397D2BA1D0DDD8C00BB2784 /* demux.h in Headers */, 321B37922083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, - 80377C8F1F2F666400F89830 /* rescaler_utils.h in Headers */, - 4397D2BD1D0DDD8C00BB2784 /* types.h in Headers */, 4397D2C01D0DDD8C00BB2784 /* SDWebImage.h in Headers */, - 4397D2C11D0DDD8C00BB2784 /* format_constants.h in Headers */, 32F21B5620788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, - 80377C8D1F2F666400F89830 /* random_utils.h in Headers */, 4397D2C31D0DDD8C00BB2784 /* SDWebImageManager.h in Headers */, - 323F8B551F38EF770092B609 /* backward_references_enc.h in Headers */, 327054D9206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, - 80377C811F2F666400F89830 /* endian_inl_utils.h in Headers */, 321E60991F38E8ED00405457 /* SDImageIOCoder.h in Headers */, - 323F8B8B1F38EF770092B609 /* histogram_enc.h in Headers */, 4397D2C41D0DDD8C00BB2784 /* SDImageCache.h in Headers */, 3248476E201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 4397D2C51D0DDD8C00BB2784 /* UIImageView+WebCache.h in Headers */, 3290FA091FA478AF0047D20C /* SDImageFrame.h in Headers */, 4369C27C1D9807EC007E863A /* UIView+WebCache.h in Headers */, - 80377EE21F2F66D500F89830 /* vp8i_dec.h in Headers */, - 80377C8B1F2F666400F89830 /* quant_levels_utils.h in Headers */, 4397D2C81D0DDD8C00BB2784 /* SDWebImageCompat.h in Headers */, 4397D2CB1D0DDD8C00BB2784 /* UIImageView+HighlightedWebCache.h in Headers */, - 4397D2CC1D0DDD8C00BB2784 /* mux.h in Headers */, - 80377C911F2F666400F89830 /* thread_utils.h in Headers */, 320CAE1A2086F50500CFFC80 /* SDWebImageError.h in Headers */, 32FDE8832088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, 4397D2D01D0DDD8C00BB2784 /* SDWebImageDownloaderOperation.h in Headers */, - 4397D2D11D0DDD8C00BB2784 /* decode.h in Headers */, - 80377E481F2F66A800F89830 /* dsp.h in Headers */, - 323F8BE91F38EF770092B609 /* vp8li_enc.h in Headers */, 3248477A201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 329A185E1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, 320224BB203979BA00E9F285 /* SDAnimatedImageRep.h in Headers */, 328BB6C62082581100760D6C /* SDDiskCache.h in Headers */, - 32FDE89420888726008D7530 /* SDImageWebPCoder.h in Headers */, - 80377E761F2F66A800F89830 /* yuv.h in Headers */, - 80377C7A1F2F666400F89830 /* bit_reader_inl_utils.h in Headers */, - 80377E631F2F66A800F89830 /* lossless.h in Headers */, 32CF1C0C1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, 43A918691D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 4397D2D81D0DDD8C00BB2784 /* UIButton+WebCache.h in Headers */, 32F7C0742030114C00873181 /* SDImageTransformer.h in Headers */, - 80377E641F2F66A800F89830 /* mips_macro.h in Headers */, 328BB6D22082581100760D6C /* SDMemoryCache.h in Headers */, - 323F8BDD1F38EF770092B609 /* vp8i_enc.h in Headers */, - 323F8B671F38EF770092B609 /* cost_enc.h in Headers */, 321B37862083290E00C0EA77 /* SDImageLoader.h in Headers */, - 80377EE11F2F66D500F89830 /* vp8_dec.h in Headers */, - 80377EE41F2F66D500F89830 /* vp8li_dec.h in Headers */, - 80377C931F2F666400F89830 /* utils.h in Headers */, - 80377C801F2F666400F89830 /* color_cache_utils.h in Headers */, - 80377C891F2F666400F89830 /* quant_levels_dec_utils.h in Headers */, - 323F8C131F38EF770092B609 /* muxi.h in Headers */, - 80377E3A1F2F66A800F89830 /* common_sse2.h in Headers */, 4397D2D91D0DDD8C00BB2784 /* SDWebImagePrefetcher.h in Headers */, - 80377C871F2F666400F89830 /* huffman_utils.h in Headers */, 32C0FDE62013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 4397D2DA1D0DDD8C00BB2784 /* UIView+WebCacheOperation.h in Headers */, - 80377E661F2F66A800F89830 /* neon.h in Headers */, 4397D2DB1D0DDD8C00BB2784 /* UIImage+MultiFormat.h in Headers */, 4397D2DC1D0DDD8C00BB2784 /* SDWebImageOperation.h in Headers */, 4397D2F61D0DE2DF00BB2784 /* NSImage+Compatibility.h in Headers */, 4397D2E11D0DDD8C00BB2784 /* SDWebImageDownloader.h in Headers */, - 323F8BFB1F38EF770092B609 /* animi.h in Headers */, - 4397D2E61D0DDD8C00BB2784 /* encode.h in Headers */, - 32FDE89A20888726008D7530 /* UIImage+WebP.h in Headers */, - 80377C7C1F2F666400F89830 /* bit_reader_utils.h in Headers */, 321E608B1F38E8C800405457 /* SDImageCoder.h in Headers */, - 323F8B731F38EF770092B609 /* delta_palettization_enc.h in Headers */, 321E60C31F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 32D122352080B2EB003685A3 /* SDImageCachesManager.h in Headers */, 32484768201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, - 80377E561F2F66A800F89830 /* lossless_common.h in Headers */, 325312CD200F09910046BF1E /* SDWebImageTransition.h in Headers */, 4397D2EA1D0DDD8C00BB2784 /* UIImage+GIF.h in Headers */, 4397D2EB1D0DDD8C00BB2784 /* NSData+ImageContentType.h in Headers */, - 80377C851F2F666400F89830 /* huffman_encode_utils.h in Headers */, 321DB3612011D4D70015D2CB /* NSButton+WebCache.h in Headers */, 807A122D1F89636300EC2A9B /* SDImageCodersManager.h in Headers */, - 4397D2ED1D0DDD8C00BB2784 /* mux_types.h in Headers */, - 80377C831F2F666400F89830 /* filters_utils.h in Headers */, - 80377E651F2F66A800F89830 /* msa_macro.h in Headers */, 328BB6A12081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2725,96 +1192,51 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 80377D971F2F66A700F89830 /* neon.h in Headers */, - 80377DA71F2F66A700F89830 /* yuv.h in Headers */, - 80377D951F2F66A700F89830 /* mips_macro.h in Headers */, - 80377C3D1F2F666300F89830 /* quant_levels_utils.h in Headers */, - 323F8B521F38EF770092B609 /* backward_references_enc.h in Headers */, - 4317394F1CDFC8B70008FEB9 /* demux.h in Headers */, 32D122202080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AC2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, - 80377C301F2F666300F89830 /* bit_writer_utils.h in Headers */, 321B378F2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, - 431739541CDFC8B70008FEB9 /* types.h in Headers */, - 323F8BE61F38EF770092B609 /* vp8li_enc.h in Headers */, 329A185B1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, 4369C2791D9807EC007E863A /* UIView+WebCache.h in Headers */, 32F21B5320788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, - 80377D871F2F66A700F89830 /* lossless_common.h in Headers */, 321E60961F38E8ED00405457 /* SDImageIOCoder.h in Headers */, 4A2CAE041AB4BB5400B6BC39 /* SDWebImage.h in Headers */, 327054D6206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, - 431739511CDFC8B70008FEB9 /* format_constants.h in Headers */, 43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, - 323F8B701F38EF770092B609 /* delta_palettization_enc.h in Headers */, 3290FA061FA478AF0047D20C /* SDImageFrame.h in Headers */, 324DF4B6200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 807A122A1F89636300EC2A9B /* SDImageCodersManager.h in Headers */, - 80377EB61F2F66D400F89830 /* webpi_dec.h in Headers */, 4A2CAE211AB4BB7000B6BC39 /* SDWebImageManager.h in Headers */, - 80377D941F2F66A700F89830 /* lossless.h in Headers */, - 80377C3F1F2F666300F89830 /* random_utils.h in Headers */, 4A2CAE1F1AB4BB6C00B6BC39 /* SDImageCache.h in Headers */, 4A2CAE351AB4BB7500B6BC39 /* UIImageView+WebCache.h in Headers */, - 80377D6B1F2F66A700F89830 /* common_sse2.h in Headers */, 320CAE172086F50500CFFC80 /* SDWebImageError.h in Headers */, 4A2CAE181AB4BB6400B6BC39 /* SDWebImageCompat.h in Headers */, 32FDE8812088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, - 80377D961F2F66A700F89830 /* msa_macro.h in Headers */, - 80377C391F2F666300F89830 /* huffman_utils.h in Headers */, 4A2CAE331AB4BB7500B6BC39 /* UIImageView+HighlightedWebCache.h in Headers */, - 431739521CDFC8B70008FEB9 /* mux.h in Headers */, - 323F8B641F38EF770092B609 /* cost_enc.h in Headers */, 328BB6C32082581100760D6C /* SDDiskCache.h in Headers */, 4A2CAE1D1AB4BB6800B6BC39 /* SDWebImageDownloaderOperation.h in Headers */, - 32FDE89120888726008D7530 /* SDImageWebPCoder.h in Headers */, - 323F8BDA1F38EF770092B609 /* vp8i_enc.h in Headers */, - 4317394E1CDFC8B70008FEB9 /* decode.h in Headers */, - 80377C2C1F2F666300F89830 /* bit_reader_inl_utils.h in Headers */, 4A2CAE2B1AB4BB7500B6BC39 /* UIButton+WebCache.h in Headers */, 4A2CAE251AB4BB7000B6BC39 /* SDWebImagePrefetcher.h in Headers */, - 80377C431F2F666300F89830 /* thread_utils.h in Headers */, 328BB6CF2082581100760D6C /* SDMemoryCache.h in Headers */, 321E60881F38E8C800405457 /* SDImageCoder.h in Headers */, 4A2CAE371AB4BB7500B6BC39 /* UIView+WebCacheOperation.h in Headers */, 321B37832083290E00C0EA77 /* SDImageLoader.h in Headers */, - 80377C2E1F2F666300F89830 /* bit_reader_utils.h in Headers */, - 80377C371F2F666300F89830 /* huffman_encode_utils.h in Headers */, 32484777201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 4A2CAE2F1AB4BB7500B6BC39 /* UIImage+MultiFormat.h in Headers */, 325312CA200F09910046BF1E /* SDWebImageTransition.h in Headers */, - 323F8C101F38EF770092B609 /* muxi.h in Headers */, - 80377EB41F2F66D400F89830 /* vp8li_dec.h in Headers */, 4A2CAE1A1AB4BB6400B6BC39 /* SDWebImageOperation.h in Headers */, - 80377C331F2F666300F89830 /* endian_inl_utils.h in Headers */, 32484765201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 321E60A41F38E8F600405457 /* SDImageGIFCoder.h in Headers */, 32CF1C091FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, 4A2CAE1B1AB4BB6800B6BC39 /* SDWebImageDownloader.h in Headers */, - 431739501CDFC8B70008FEB9 /* encode.h in Headers */, - 323F8B881F38EF770092B609 /* histogram_enc.h in Headers */, - 80377EB21F2F66D400F89830 /* vp8i_dec.h in Headers */, - 80377EAA1F2F66D400F89830 /* common_dec.h in Headers */, - 80377C451F2F666300F89830 /* utils.h in Headers */, - 80377C411F2F666300F89830 /* rescaler_utils.h in Headers */, - 32FDE89720888726008D7530 /* UIImage+WebP.h in Headers */, 3248476B201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, - 323F8BF81F38EF770092B609 /* animi.h in Headers */, 32D122322080B2EB003685A3 /* SDImageCachesManager.h in Headers */, - 80377C351F2F666300F89830 /* filters_utils.h in Headers */, 32F7C0862030719600873181 /* UIImage+Transform.h in Headers */, - 80377C321F2F666300F89830 /* color_cache_utils.h in Headers */, 321E60C01F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 32C0FDE32013426C001B8F2D /* SDWebImageIndicator.h in Headers */, - 80377D791F2F66A700F89830 /* dsp.h in Headers */, - 80377EA81F2F66D400F89830 /* alphai_dec.h in Headers */, 32F7C0712030114C00873181 /* SDImageTransformer.h in Headers */, 4A2CAE2D1AB4BB7500B6BC39 /* UIImage+GIF.h in Headers */, - 80377C3B1F2F666300F89830 /* quant_levels_dec_utils.h in Headers */, - 80377EB11F2F66D400F89830 /* vp8_dec.h in Headers */, 4A2CAE291AB4BB7500B6BC39 /* NSData+ImageContentType.h in Headers */, - 431739531CDFC8B70008FEB9 /* mux_types.h in Headers */, 328BB69E2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2823,48 +1245,28 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 431738C21CDFC2660008FEB9 /* mux_types.h in Headers */, - 431738BE1CDFC2660008FEB9 /* demux.h in Headers */, - 80377BFC1F2F665300F89830 /* bit_writer_utils.h in Headers */, 32CF1C071FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, 32F7C0842030719600873181 /* UIImage+Transform.h in Headers */, - 431738BF1CDFC2660008FEB9 /* encode.h in Headers */, 53761316155AD0D5005750A4 /* SDImageCache.h in Headers */, - 323F8C0E1F38EF770092B609 /* muxi.h in Headers */, 325312C8200F09910046BF1E /* SDWebImageTransition.h in Headers */, 32C0FDE12013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 321E60A21F38E8F600405457 /* SDImageGIFCoder.h in Headers */, 5D5B9142188EE8DD006D06BD /* NSData+ImageContentType.h in Headers */, - 80377BFE1F2F665300F89830 /* color_cache_utils.h in Headers */, 328BB6C12082581100760D6C /* SDDiskCache.h in Headers */, - 431738C11CDFC2660008FEB9 /* mux.h in Headers */, - 80377D0A1F2F66A100F89830 /* lossless.h in Headers */, 53761318155AD0D5005750A4 /* SDWebImageCompat.h in Headers */, - 80377D0D1F2F66A100F89830 /* neon.h in Headers */, - 431738C31CDFC2660008FEB9 /* types.h in Headers */, - 80377D0C1F2F66A100F89830 /* msa_macro.h in Headers */, 3290FA041FA478AF0047D20C /* SDImageFrame.h in Headers */, - 80377D1D1F2F66A100F89830 /* yuv.h in Headers */, 807A12281F89636300EC2A9B /* SDImageCodersManager.h in Headers */, 32B9B537206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, - 80377C051F2F665300F89830 /* huffman_utils.h in Headers */, - 80377E881F2F66D000F89830 /* alphai_dec.h in Headers */, 32484775201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 321E60941F38E8ED00405457 /* SDImageIOCoder.h in Headers */, - 431738BD1CDFC2660008FEB9 /* decode.h in Headers */, - 80377D0B1F2F66A100F89830 /* mips_macro.h in Headers */, 329A18591FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, 32D122302080B2EB003685A3 /* SDImageCachesManager.h in Headers */, 5376131A155AD0D5005750A4 /* SDWebImageDownloader.h in Headers */, 328BB6CD2082581100760D6C /* SDMemoryCache.h in Headers */, 4369C2771D9807EC007E863A /* UIView+WebCache.h in Headers */, 328BB6AA2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, - 80377CEF1F2F66A100F89830 /* dsp.h in Headers */, 32F21B5120788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, - 80377C011F2F665300F89830 /* filters_utils.h in Headers */, 5376131C155AD0D5005750A4 /* SDWebImageManager.h in Headers */, - 80377BFF1F2F665300F89830 /* endian_inl_utils.h in Headers */, - 80377C0F1F2F665300F89830 /* thread_utils.h in Headers */, 32FDE8802088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, 321E60BE1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 5376131E155AD0D5005750A4 /* SDWebImagePrefetcher.h in Headers */, @@ -2872,47 +1274,22 @@ 321B378D2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, 32FDE8A220888789008D7530 /* SDWebImage.h in Headers */, 324DF4B4200A14DC008A84CC /* SDWebImageDefine.h in Headers */, - 80377CE11F2F66A100F89830 /* common_sse2.h in Headers */, - 80377C0B1F2F665300F89830 /* random_utils.h in Headers */, - 80377E921F2F66D000F89830 /* vp8i_dec.h in Headers */, 5376131F155AD0D5005750A4 /* UIButton+WebCache.h in Headers */, 327054D4206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, 53761320155AD0D5005750A4 /* UIImageView+WebCache.h in Headers */, 328BB69C2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, 530E49E816464C25002868E7 /* SDWebImageOperation.h in Headers */, 32484769201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, - 80377E961F2F66D000F89830 /* webpi_dec.h in Headers */, - 80377BF81F2F665300F89830 /* bit_reader_inl_utils.h in Headers */, 530E49EA16464C7C002868E7 /* SDWebImageDownloaderOperation.h in Headers */, ABBE71A718C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h in Headers */, - 80377C071F2F665300F89830 /* quant_levels_dec_utils.h in Headers */, - 323F8BD81F38EF770092B609 /* vp8i_enc.h in Headers */, - 80377E941F2F66D000F89830 /* vp8li_dec.h in Headers */, - 80377CFD1F2F66A100F89830 /* lossless_common.h in Headers */, - 431738C01CDFC2660008FEB9 /* format_constants.h in Headers */, - 323F8B621F38EF770092B609 /* cost_enc.h in Headers */, - 323F8BE41F38EF770092B609 /* vp8li_enc.h in Headers */, - 32FDE88F20888726008D7530 /* SDImageWebPCoder.h in Headers */, 320CAE152086F50500CFFC80 /* SDWebImageError.h in Headers */, - 323F8B861F38EF770092B609 /* histogram_enc.h in Headers */, 321B37812083290E00C0EA77 /* SDImageLoader.h in Headers */, - 323F8BF61F38EF770092B609 /* animi.h in Headers */, 321E60861F38E8C800405457 /* SDImageCoder.h in Headers */, - 80377C0D1F2F665300F89830 /* rescaler_utils.h in Headers */, 32484763201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, - 80377E911F2F66D000F89830 /* vp8_dec.h in Headers */, - 323F8B6E1F38EF770092B609 /* delta_palettization_enc.h in Headers */, 32D1221E2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, - 80377E8A1F2F66D000F89830 /* common_dec.h in Headers */, AB615303192DA24600A2D8E9 /* UIView+WebCacheOperation.h in Headers */, - 32FDE89520888726008D7530 /* UIImage+WebP.h in Headers */, - 323F8B501F38EF770092B609 /* backward_references_enc.h in Headers */, - 80377C111F2F665300F89830 /* utils.h in Headers */, - 80377BFA1F2F665300F89830 /* bit_reader_utils.h in Headers */, - 80377C091F2F665300F89830 /* quant_levels_utils.h in Headers */, A18A6CC7172DC28500419892 /* UIImage+GIF.h in Headers */, 53EDFB8A17623F7C00698166 /* UIImage+MultiFormat.h in Headers */, - 80377C031F2F665300F89830 /* huffman_encode_utils.h in Headers */, 43A918641D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3034,7 +1411,7 @@ 53922D66148C55810056699D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0900; + LastUpgradeCheck = 0940; ORGANIZATIONNAME = Dailymotion; TargetAttributes = { 00733A4B1BC487C000A5A117 = { @@ -3134,166 +1511,52 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 80377DD31F2F66A700F89830 /* lossless_enc.c in Sources */, - 32FDE88C20888726008D7530 /* UIImage+WebP.m in Sources */, - 323F8BBD1F38EF770092B609 /* predictor_enc.c in Sources */, 3290FA0D1FA478AF0047D20C /* SDImageFrame.m in Sources */, - 80377DBD1F2F66A700F89830 /* dec.c in Sources */, 00733A561BC4880000A5A117 /* SDWebImageDownloaderOperation.m in Sources */, - 80377DE71F2F66A700F89830 /* upsampling.c in Sources */, 321E60C71F38E91700405457 /* UIImage+ForceDecode.m in Sources */, - 323F8BB71F38EF770092B609 /* picture_tools_enc.c in Sources */, - 80377C5A1F2F666300F89830 /* rescaler_utils.c in Sources */, - 323F8B8F1F38EF770092B609 /* iterator_enc.c in Sources */, - 80377DEA1F2F66A700F89830 /* yuv_sse2.c in Sources */, - 80377DB91F2F66A700F89830 /* dec_msa.c in Sources */, - 323F8BE11F38EF770092B609 /* vp8l_enc.c in Sources */, - 80377DAB1F2F66A700F89830 /* alpha_processing_sse41.c in Sources */, - 80377DBA1F2F66A700F89830 /* dec_neon.c in Sources */, 328BB6A52081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, - 80377C5C1F2F666300F89830 /* thread_utils.c in Sources */, 00733A5A1BC4880000A5A117 /* SDWebImagePrefetcher.m in Sources */, - 80377DBF1F2F66A700F89830 /* enc_avx2.c in Sources */, - 80377DC71F2F66A700F89830 /* filters_mips_dsp_r2.c in Sources */, - 323F8BC91F38EF770092B609 /* syntax_enc.c in Sources */, - 80377DC01F2F66A700F89830 /* enc_mips_dsp_r2.c in Sources */, - 80377DA91F2F66A700F89830 /* alpha_processing_neon.c in Sources */, 320CAE1E2086F50500CFFC80 /* SDWebImageError.m in Sources */, - 80377DB71F2F66A700F89830 /* dec_mips_dsp_r2.c in Sources */, - 80377DC31F2F66A700F89830 /* enc_neon.c in Sources */, - 80377C501F2F666300F89830 /* huffman_encode_utils.c in Sources */, - 80377DE51F2F66A700F89830 /* upsampling_neon.c in Sources */, 32CF1C101FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, - 80377DAE1F2F66A700F89830 /* argb_sse2.c in Sources */, - 323F8B7D1F38EF770092B609 /* frame_enc.c in Sources */, 328BB6D62082581100760D6C /* SDMemoryCache.m in Sources */, - 80377EBB1F2F66D500F89830 /* frame_dec.c in Sources */, 32F7C0782030114C00873181 /* SDImageTransformer.m in Sources */, - 80377DAF1F2F66A700F89830 /* argb.c in Sources */, - 323F8B6B1F38EF770092B609 /* delta_palettization_enc.c in Sources */, 00733A5B1BC4880000A5A117 /* NSData+ImageContentType.m in Sources */, - 323F8B5F1F38EF770092B609 /* cost_enc.c in Sources */, - 43C8929E1D9D6DDA0022038D /* anim_decode.c in Sources */, - 80377EB91F2F66D400F89830 /* buffer_dec.c in Sources */, - 80377DCF1F2F66A700F89830 /* lossless_enc_msa.c in Sources */, - 80377DD51F2F66A700F89830 /* lossless_msa.c in Sources */, - 80377C4E1F2F666300F89830 /* filters_utils.c in Sources */, - 80377DEB1F2F66A700F89830 /* yuv.c in Sources */, 3237F9E920161AE000A88143 /* NSImage+Compatibility.m in Sources */, 32C0FDEA2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 32F21B5A20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 00733A551BC4880000A5A117 /* SDWebImageDownloader.m in Sources */, - 80377EB71F2F66D400F89830 /* alpha_dec.c in Sources */, - 80377DC61F2F66A700F89830 /* enc.c in Sources */, - 80377DD41F2F66A700F89830 /* lossless_mips_dsp_r2.c in Sources */, - 323F8B771F38EF770092B609 /* filter_enc.c in Sources */, - 80377DDD1F2F66A700F89830 /* rescaler_mips_dsp_r2.c in Sources */, - 323F8B4D1F38EF770092B609 /* backward_references_enc.c in Sources */, - 80377DCD1F2F66A700F89830 /* lossless_enc_mips_dsp_r2.c in Sources */, - 323F8BF31F38EF770092B609 /* anim_encode.c in Sources */, - 80377DD71F2F66A700F89830 /* lossless_sse2.c in Sources */, - 80377DA81F2F66A700F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, - 80377DB11F2F66A700F89830 /* cost_mips_dsp_r2.c in Sources */, 321B37962083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, - 80377C581F2F666300F89830 /* random_utils.c in Sources */, - 323F8B591F38EF770092B609 /* config_enc.c in Sources */, - 80377DE91F2F66A700F89830 /* yuv_mips32.c in Sources */, - 80377DB41F2F66A700F89830 /* cost.c in Sources */, - 80377DE31F2F66A700F89830 /* upsampling_mips_dsp_r2.c in Sources */, - 80377EBD1F2F66D500F89830 /* io_dec.c in Sources */, - 80377EBC1F2F66D500F89830 /* idec_dec.c in Sources */, 32F7C0812030719600873181 /* UIImage+Transform.m in Sources */, - 323F8B991F38EF770092B609 /* near_lossless_enc.c in Sources */, - 80377DE81F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */, - 80377EC31F2F66D500F89830 /* vp8l_dec.c in Sources */, 327054DD206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, 325312D1200F09910046BF1E /* SDWebImageTransition.m in Sources */, 321E609D1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, - 323F8B9F1F38EF770092B609 /* picture_csp_enc.c in Sources */, - 43C892A31D9D6DDD0022038D /* demux.c in Sources */, 00733A611BC4880000A5A117 /* UIImageView+WebCache.m in Sources */, - 80377EBF1F2F66D500F89830 /* tree_dec.c in Sources */, - 80377DD21F2F66A700F89830 /* lossless_enc_sse41.c in Sources */, - 80377DB31F2F66A700F89830 /* cost_sse2.c in Sources */, 328BB6CA2082581100760D6C /* SDDiskCache.m in Sources */, 32484760201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, - 80377DDE1F2F66A700F89830 /* rescaler_mips32.c in Sources */, - 80377DCA1F2F66A700F89830 /* filters_sse2.c in Sources */, - 80377EBE1F2F66D500F89830 /* quant_dec.c in Sources */, 32D1222D2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, - 80377DB61F2F66A700F89830 /* dec_clip_tables.c in Sources */, - 80377C5E1F2F666300F89830 /* utils.c in Sources */, 32B9B540206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, - 323F8C0B1F38EF770092B609 /* muxedit.c in Sources */, - 80377DC11F2F66A700F89830 /* enc_mips32.c in Sources */, - 80377DBC1F2F66A700F89830 /* dec_sse41.c in Sources */, - 80377DCE1F2F66A700F89830 /* lossless_enc_mips32.c in Sources */, 3248477E201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, - 80377DCB1F2F66A700F89830 /* filters.c in Sources */, - 80377DAA1F2F66A700F89830 /* alpha_processing_sse2.c in Sources */, 43A9186E1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, - 80377C471F2F666300F89830 /* bit_reader_utils.c in Sources */, 321E60AB1F38E8F600405457 /* SDImageGIFCoder.m in Sources */, - 323F8BD51F38EF770092B609 /* tree_enc.c in Sources */, - 80377DBB1F2F66A700F89830 /* dec_sse2.c in Sources */, - 323F8B831F38EF770092B609 /* histogram_enc.c in Sources */, 321E608F1F38E8C800405457 /* SDImageCoder.m in Sources */, 00733A581BC4880000A5A117 /* SDWebImageManager.m in Sources */, - 323F8B411F38EF770092B609 /* alpha_enc.c in Sources */, - 323F8BC31F38EF770092B609 /* quant_enc.c in Sources */, 00733A541BC4880000A5A117 /* SDWebImageCompat.m in Sources */, - 80377DDF1F2F66A700F89830 /* rescaler_msa.c in Sources */, 32FDE87E2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */, - 80377DE41F2F66A700F89830 /* upsampling_msa.c in Sources */, 00733A621BC4880000A5A117 /* UIView+WebCacheOperation.m in Sources */, - 80377DC21F2F66A700F89830 /* enc_msa.c in Sources */, - 80377DC91F2F66A700F89830 /* filters_neon.c in Sources */, - 80377DC51F2F66A700F89830 /* enc_sse41.c in Sources */, - 80377DE61F2F66A700F89830 /* upsampling_sse2.c in Sources */, - 80377C561F2F666300F89830 /* quant_levels_utils.c in Sources */, - 323F8BCF1F38EF770092B609 /* token_enc.c in Sources */, - 80377DD11F2F66A700F89830 /* lossless_enc_sse2.c in Sources */, 321B378A2083290E00C0EA77 /* SDImageLoader.m in Sources */, 32484772201775F600AF9E5A /* SDAnimatedImage.m in Sources */, - 323F8C1D1F38EF770092B609 /* muxread.c in Sources */, 807A12311F89636300EC2A9B /* SDImageCodersManager.m in Sources */, - 80377C491F2F666300F89830 /* bit_writer_utils.c in Sources */, - 323F8B471F38EF770092B609 /* analysis_enc.c in Sources */, - 80377DB51F2F66A700F89830 /* cpu.c in Sources */, - 80377EC51F2F66D500F89830 /* webp_dec.c in Sources */, - 80377DD61F2F66A700F89830 /* lossless_neon.c in Sources */, 32D122272080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, 00733A5C1BC4880000A5A117 /* UIButton+WebCache.m in Sources */, - 80377EC01F2F66D500F89830 /* vp8_dec.c in Sources */, - 80377C521F2F666300F89830 /* huffman_utils.c in Sources */, - 80377DD81F2F66A700F89830 /* lossless.c in Sources */, - 32FDE89E20888726008D7530 /* SDImageWebPCoder.m in Sources */, - 80377DE11F2F66A700F89830 /* rescaler_sse2.c in Sources */, 324DF4BD200A14DC008A84CC /* SDWebImageDefine.m in Sources */, - 80377DAC1F2F66A700F89830 /* alpha_processing.c in Sources */, - 80377DE01F2F66A700F89830 /* rescaler_neon.c in Sources */, - 80377C541F2F666300F89830 /* quant_levels_dec_utils.c in Sources */, - 80377C4B1F2F666300F89830 /* color_cache_utils.c in Sources */, - 80377DB81F2F66A700F89830 /* dec_mips32.c in Sources */, - 323F8BED1F38EF770092B609 /* webp_enc.c in Sources */, - 80377DC41F2F66A700F89830 /* enc_sse2.c in Sources */, 00733A5D1BC4880000A5A117 /* UIImage+GIF.m in Sources */, - 323F8C171F38EF770092B609 /* muxinternal.c in Sources */, - 323F8BB11F38EF770092B609 /* picture_rescale_enc.c in Sources */, - 80377DB21F2F66A700F89830 /* cost_mips32.c in Sources */, 32EB6D90206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, - 80377DC81F2F66A700F89830 /* filters_msa.c in Sources */, 00733A571BC4880000A5A117 /* SDImageCache.m in Sources */, 4369C2811D9807EC007E863A /* UIView+WebCache.m in Sources */, 00733A5E1BC4880000A5A117 /* UIImage+MultiFormat.m in Sources */, - 80377DD01F2F66A700F89830 /* lossless_enc_neon.c in Sources */, - 80377DE21F2F66A700F89830 /* rescaler.c in Sources */, 329A18621FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, - 80377DAD1F2F66A700F89830 /* argb_mips_dsp_r2.c in Sources */, 328BB6B32081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, 00733A601BC4880000A5A117 /* UIImageView+HighlightedWebCache.m in Sources */, - 323F8BAB1F38EF770092B609 /* picture_psnr_enc.c in Sources */, - 323F8BA51F38EF770092B609 /* picture_enc.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3301,165 +1564,51 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 80377E9F1F2F66D400F89830 /* tree_dec.c in Sources */, - 80377D2C1F2F66A700F89830 /* dec_clip_tables.c in Sources */, - 323F8B971F38EF770092B609 /* near_lossless_enc.c in Sources */, - 80377D531F2F66A700F89830 /* rescaler_mips_dsp_r2.c in Sources */, - 43C8929C1D9D6DD90022038D /* anim_decode.c in Sources */, - 80377D311F2F66A700F89830 /* dec_sse2.c in Sources */, 4314D1231D0E0E3B004B36C9 /* SDImageCache.m in Sources */, - 80377C151F2F666300F89830 /* bit_writer_utils.c in Sources */, - 323F8BEB1F38EF770092B609 /* webp_enc.c in Sources */, - 80377EA01F2F66D400F89830 /* vp8_dec.c in Sources */, - 80377EA31F2F66D400F89830 /* vp8l_dec.c in Sources */, - 80377E9D1F2F66D400F89830 /* io_dec.c in Sources */, 329A18601FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, - 80377D541F2F66A700F89830 /* rescaler_mips32.c in Sources */, - 80377D331F2F66A700F89830 /* dec.c in Sources */, 32EB6D92206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, - 323F8BAF1F38EF770092B609 /* picture_rescale_enc.c in Sources */, - 80377D3F1F2F66A700F89830 /* filters_neon.c in Sources */, - 80377D3E1F2F66A700F89830 /* filters_msa.c in Sources */, - 80377D241F2F66A700F89830 /* argb_sse2.c in Sources */, - 323F8B3F1F38EF770092B609 /* alpha_enc.c in Sources */, - 80377D4D1F2F66A700F89830 /* lossless_sse2.c in Sources */, - 80377D271F2F66A700F89830 /* cost_mips_dsp_r2.c in Sources */, - 80377D2D1F2F66A700F89830 /* dec_mips_dsp_r2.c in Sources */, - 80377D301F2F66A700F89830 /* dec_neon.c in Sources */, - 80377D2B1F2F66A700F89830 /* cpu.c in Sources */, - 80377EA51F2F66D400F89830 /* webp_dec.c in Sources */, - 80377E9E1F2F66D400F89830 /* quant_dec.c in Sources */, - 80377D4B1F2F66A700F89830 /* lossless_msa.c in Sources */, - 323F8B5D1F38EF770092B609 /* cost_enc.c in Sources */, - 80377D3B1F2F66A700F89830 /* enc_sse41.c in Sources */, 321E608D1F38E8C800405457 /* SDImageCoder.m in Sources */, - 80377D3A1F2F66A700F89830 /* enc_sse2.c in Sources */, - 80377D381F2F66A700F89830 /* enc_msa.c in Sources */, 4314D1311D0E0E3B004B36C9 /* SDWebImageDownloader.m in Sources */, - 323F8B811F38EF770092B609 /* histogram_enc.c in Sources */, - 80377D441F2F66A700F89830 /* lossless_enc_mips32.c in Sources */, 4369C27F1D9807EC007E863A /* UIView+WebCache.m in Sources */, - 80377D4A1F2F66A700F89830 /* lossless_mips_dsp_r2.c in Sources */, - 32FDE88A20888726008D7530 /* UIImage+WebP.m in Sources */, - 80377D4C1F2F66A700F89830 /* lossless_neon.c in Sources */, - 80377D591F2F66A700F89830 /* upsampling_mips_dsp_r2.c in Sources */, - 323F8BDF1F38EF770092B609 /* vp8l_enc.c in Sources */, - 80377D3D1F2F66A700F89830 /* filters_mips_dsp_r2.c in Sources */, - 323F8B751F38EF770092B609 /* filter_enc.c in Sources */, 32D122252080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, - 80377D401F2F66A700F89830 /* filters_sse2.c in Sources */, - 80377D1E1F2F66A700F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, - 80377D291F2F66A700F89830 /* cost_sse2.c in Sources */, - 80377D601F2F66A700F89830 /* yuv_sse2.c in Sources */, - 80377C281F2F666300F89830 /* thread_utils.c in Sources */, 3290FA0B1FA478AF0047D20C /* SDImageFrame.m in Sources */, - 80377C2A1F2F666300F89830 /* utils.c in Sources */, - 323F8B4B1F38EF770092B609 /* backward_references_enc.c in Sources */, 807A122F1F89636300EC2A9B /* SDImageCodersManager.m in Sources */, 4314D1361D0E0E3B004B36C9 /* SDWebImageManager.m in Sources */, 321E609B1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, - 80377D4E1F2F66A700F89830 /* lossless.c in Sources */, - 80377D351F2F66A700F89830 /* enc_avx2.c in Sources */, - 80377D201F2F66A700F89830 /* alpha_processing_sse2.c in Sources */, - 323F8C1B1F38EF770092B609 /* muxread.c in Sources */, - 80377D581F2F66A700F89830 /* rescaler.c in Sources */, - 80377D361F2F66A700F89830 /* enc_mips_dsp_r2.c in Sources */, - 323F8BA31F38EF770092B609 /* picture_enc.c in Sources */, 4314D1371D0E0E3B004B36C9 /* SDWebImagePrefetcher.m in Sources */, - 80377C241F2F666300F89830 /* random_utils.c in Sources */, - 80377D2A1F2F66A700F89830 /* cost.c in Sources */, - 80377D411F2F66A700F89830 /* filters.c in Sources */, - 80377D221F2F66A700F89830 /* alpha_processing.c in Sources */, 320CAE1C2086F50500CFFC80 /* SDWebImageError.m in Sources */, - 80377D391F2F66A700F89830 /* enc_neon.c in Sources */, - 80377D5B1F2F66A700F89830 /* upsampling_neon.c in Sources */, - 80377D5F1F2F66A700F89830 /* yuv_mips32.c in Sources */, - 80377D3C1F2F66A700F89830 /* enc.c in Sources */, 4314D13B1D0E0E3B004B36C9 /* UIButton+WebCache.m in Sources */, 328BB6A32081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 32F21B5820788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 321E60C51F38E91700405457 /* UIImage+ForceDecode.m in Sources */, - 80377D461F2F66A700F89830 /* lossless_enc_neon.c in Sources */, - 80377E9B1F2F66D400F89830 /* frame_dec.c in Sources */, - 80377C1C1F2F666300F89830 /* huffman_encode_utils.c in Sources */, - 323F8B451F38EF770092B609 /* analysis_enc.c in Sources */, 328BB6C82082581100760D6C /* SDDiskCache.m in Sources */, - 80377C261F2F666300F89830 /* rescaler_utils.c in Sources */, - 323F8BBB1F38EF770092B609 /* predictor_enc.c in Sources */, 325312CF200F09910046BF1E /* SDWebImageTransition.m in Sources */, - 80377D2F1F2F66A700F89830 /* dec_msa.c in Sources */, - 323F8C151F38EF770092B609 /* muxinternal.c in Sources */, - 80377D571F2F66A700F89830 /* rescaler_sse2.c in Sources */, 32D1222B2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, - 43C892A11D9D6DDC0022038D /* demux.c in Sources */, - 80377C131F2F666300F89830 /* bit_reader_utils.c in Sources */, - 80377E9C1F2F66D400F89830 /* idec_dec.c in Sources */, - 323F8B7B1F38EF770092B609 /* frame_enc.c in Sources */, - 80377D211F2F66A700F89830 /* alpha_processing_sse41.c in Sources */, 321B37942083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, - 323F8B8D1F38EF770092B609 /* iterator_enc.c in Sources */, 3248475E201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, - 80377D481F2F66A700F89830 /* lossless_enc_sse41.c in Sources */, 32484770201775F600AF9E5A /* SDAnimatedImage.m in Sources */, - 323F8BA91F38EF770092B609 /* picture_psnr_enc.c in Sources */, 3248477C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, - 323F8C091F38EF770092B609 /* muxedit.c in Sources */, - 80377D1F1F2F66A700F89830 /* alpha_processing_neon.c in Sources */, 32C0FDE82013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 4314D1401D0E0E3B004B36C9 /* UIImageView+WebCache.m in Sources */, 43A9186C1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, 3237F9EC20161AE000A88143 /* NSImage+Compatibility.m in Sources */, 4314D1411D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.m in Sources */, - 80377D561F2F66A700F89830 /* rescaler_neon.c in Sources */, 32B9B53E206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, 32F7C0762030114C00873181 /* SDImageTransformer.m in Sources */, - 80377D551F2F66A700F89830 /* rescaler_msa.c in Sources */, - 80377D5E1F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */, - 80377D611F2F66A700F89830 /* yuv.c in Sources */, - 323F8BC11F38EF770092B609 /* quant_enc.c in Sources */, - 323F8BB51F38EF770092B609 /* picture_tools_enc.c in Sources */, - 80377C221F2F666300F89830 /* quant_levels_utils.c in Sources */, - 80377D2E1F2F66A700F89830 /* dec_mips32.c in Sources */, - 323F8BD31F38EF770092B609 /* tree_enc.c in Sources */, 327054DB206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, - 80377D5C1F2F66A700F89830 /* upsampling_sse2.c in Sources */, - 323F8BC71F38EF770092B609 /* syntax_enc.c in Sources */, 328BB6D42082581100760D6C /* SDMemoryCache.m in Sources */, - 80377D321F2F66A700F89830 /* dec_sse41.c in Sources */, 324DF4BB200A14DC008A84CC /* SDWebImageDefine.m in Sources */, - 80377D451F2F66A700F89830 /* lossless_enc_msa.c in Sources */, - 80377C1A1F2F666300F89830 /* filters_utils.c in Sources */, - 323F8B9D1F38EF770092B609 /* picture_csp_enc.c in Sources */, 4314D14B1D0E0E3B004B36C9 /* SDWebImageCompat.m in Sources */, 328BB6B12081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, 4314D14D1D0E0E3B004B36C9 /* UIImage+GIF.m in Sources */, 32CF1C0E1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, - 323F8B571F38EF770092B609 /* config_enc.c in Sources */, - 80377D371F2F66A700F89830 /* enc_mips32.c in Sources */, - 80377D431F2F66A700F89830 /* lossless_enc_mips_dsp_r2.c in Sources */, - 323F8BCD1F38EF770092B609 /* token_enc.c in Sources */, - 80377E971F2F66D400F89830 /* alpha_dec.c in Sources */, - 323F8B691F38EF770092B609 /* delta_palettization_enc.c in Sources */, 4314D1501D0E0E3B004B36C9 /* UIView+WebCacheOperation.m in Sources */, 321E60A91F38E8F600405457 /* SDImageGIFCoder.m in Sources */, - 80377D5A1F2F66A700F89830 /* upsampling_msa.c in Sources */, - 80377D491F2F66A700F89830 /* lossless_enc.c in Sources */, - 80377C171F2F666300F89830 /* color_cache_utils.c in Sources */, 4314D1521D0E0E3B004B36C9 /* NSData+ImageContentType.m in Sources */, - 80377D231F2F66A700F89830 /* argb_mips_dsp_r2.c in Sources */, 4314D1531D0E0E3B004B36C9 /* UIImage+MultiFormat.m in Sources */, - 80377D5D1F2F66A700F89830 /* upsampling.c in Sources */, - 80377D251F2F66A700F89830 /* argb.c in Sources */, - 80377D281F2F66A700F89830 /* cost_mips32.c in Sources */, - 32FDE89C20888726008D7530 /* SDImageWebPCoder.m in Sources */, - 323F8BF11F38EF770092B609 /* anim_encode.c in Sources */, 4314D1551D0E0E3B004B36C9 /* UIImageView+HighlightedWebCache.m in Sources */, - 80377E991F2F66D400F89830 /* buffer_dec.c in Sources */, - 80377C201F2F666300F89830 /* quant_levels_dec_utils.c in Sources */, 32F7C07F2030719600873181 /* UIImage+Transform.m in Sources */, 321B37882083290E00C0EA77 /* SDImageLoader.m in Sources */, - 80377D471F2F66A700F89830 /* lossless_enc_sse2.c in Sources */, - 80377C1E1F2F666300F89830 /* huffman_utils.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3467,164 +1616,50 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 80377ECF1F2F66D500F89830 /* tree_dec.c in Sources */, - 80377DFB1F2F66A800F89830 /* dec_clip_tables.c in Sources */, - 323F8B9A1F38EF770092B609 /* near_lossless_enc.c in Sources */, - 80377E221F2F66A800F89830 /* rescaler_mips_dsp_r2.c in Sources */, 431BB68C1D06D2C1006A3455 /* SDWebImageDownloaderOperation.m in Sources */, 431BB68E1D06D2C1006A3455 /* SDWebImagePrefetcher.m in Sources */, - 80377E001F2F66A800F89830 /* dec_sse2.c in Sources */, - 80377C631F2F666400F89830 /* bit_writer_utils.c in Sources */, - 323F8BEE1F38EF770092B609 /* webp_enc.c in Sources */, - 80377ED01F2F66D500F89830 /* vp8_dec.c in Sources */, - 80377ED31F2F66D500F89830 /* vp8l_dec.c in Sources */, - 80377ECD1F2F66D500F89830 /* io_dec.c in Sources */, 329A18631FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, - 80377E231F2F66A800F89830 /* rescaler_mips32.c in Sources */, - 80377E021F2F66A800F89830 /* dec.c in Sources */, 32EB6D8F206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, - 323F8BB21F38EF770092B609 /* picture_rescale_enc.c in Sources */, - 80377E0E1F2F66A800F89830 /* filters_neon.c in Sources */, - 80377E0D1F2F66A800F89830 /* filters_msa.c in Sources */, - 80377DF31F2F66A800F89830 /* argb_sse2.c in Sources */, - 323F8B421F38EF770092B609 /* alpha_enc.c in Sources */, - 80377E1C1F2F66A800F89830 /* lossless_sse2.c in Sources */, - 80377DF61F2F66A800F89830 /* cost_mips_dsp_r2.c in Sources */, - 80377DFC1F2F66A800F89830 /* dec_mips_dsp_r2.c in Sources */, - 80377DFF1F2F66A800F89830 /* dec_neon.c in Sources */, - 80377DFA1F2F66A800F89830 /* cpu.c in Sources */, - 80377ED51F2F66D500F89830 /* webp_dec.c in Sources */, - 43C8929F1D9D6DDA0022038D /* anim_decode.c in Sources */, - 80377ECE1F2F66D500F89830 /* quant_dec.c in Sources */, - 80377E1A1F2F66A800F89830 /* lossless_msa.c in Sources */, - 323F8B601F38EF770092B609 /* cost_enc.c in Sources */, - 80377E0A1F2F66A800F89830 /* enc_sse41.c in Sources */, 321E60901F38E8C800405457 /* SDImageCoder.m in Sources */, - 80377E091F2F66A800F89830 /* enc_sse2.c in Sources */, 431BB6921D06D2C1006A3455 /* NSData+ImageContentType.m in Sources */, - 80377E071F2F66A800F89830 /* enc_msa.c in Sources */, - 323F8B841F38EF770092B609 /* histogram_enc.c in Sources */, 431BB69A1D06D2C1006A3455 /* SDWebImageDownloader.m in Sources */, - 80377E131F2F66A800F89830 /* lossless_enc_mips32.c in Sources */, - 32FDE88D20888726008D7530 /* UIImage+WebP.m in Sources */, - 80377E191F2F66A800F89830 /* lossless_mips_dsp_r2.c in Sources */, - 80377E1B1F2F66A800F89830 /* lossless_neon.c in Sources */, - 80377E281F2F66A800F89830 /* upsampling_mips_dsp_r2.c in Sources */, - 323F8BE21F38EF770092B609 /* vp8l_enc.c in Sources */, 431BB6A31D06D2C1006A3455 /* UIImageView+WebCache.m in Sources */, - 80377E0C1F2F66A800F89830 /* filters_mips_dsp_r2.c in Sources */, 32D122282080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, - 323F8B781F38EF770092B609 /* filter_enc.c in Sources */, 4369C2821D9807EC007E863A /* UIView+WebCache.m in Sources */, - 80377E0F1F2F66A800F89830 /* filters_sse2.c in Sources */, - 80377DED1F2F66A800F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, - 80377DF81F2F66A800F89830 /* cost_sse2.c in Sources */, 3290FA0E1FA478AF0047D20C /* SDImageFrame.m in Sources */, - 80377E2F1F2F66A800F89830 /* yuv_sse2.c in Sources */, 431BB6AA1D06D2C1006A3455 /* SDWebImageManager.m in Sources */, - 323F8B4E1F38EF770092B609 /* backward_references_enc.c in Sources */, 807A12321F89636300EC2A9B /* SDImageCodersManager.m in Sources */, - 80377C761F2F666400F89830 /* thread_utils.c in Sources */, 321E609E1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, - 80377E1D1F2F66A800F89830 /* lossless.c in Sources */, - 80377E041F2F66A800F89830 /* enc_avx2.c in Sources */, - 80377DEF1F2F66A800F89830 /* alpha_processing_sse2.c in Sources */, - 323F8C1E1F38EF770092B609 /* muxread.c in Sources */, - 80377E271F2F66A800F89830 /* rescaler.c in Sources */, - 80377E051F2F66A800F89830 /* enc_mips_dsp_r2.c in Sources */, - 323F8BA61F38EF770092B609 /* picture_enc.c in Sources */, - 80377C781F2F666400F89830 /* utils.c in Sources */, - 80377DF91F2F66A800F89830 /* cost.c in Sources */, - 80377E101F2F66A800F89830 /* filters.c in Sources */, - 80377DF11F2F66A800F89830 /* alpha_processing.c in Sources */, 320CAE1F2086F50500CFFC80 /* SDWebImageError.m in Sources */, - 80377E081F2F66A800F89830 /* enc_neon.c in Sources */, - 80377E2A1F2F66A800F89830 /* upsampling_neon.c in Sources */, - 80377E2E1F2F66A800F89830 /* yuv_mips32.c in Sources */, - 80377E0B1F2F66A800F89830 /* enc.c in Sources */, 431BB6AC1D06D2C1006A3455 /* SDWebImageCompat.m in Sources */, 328BB6A62081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 32F21B5B20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, - 80377E151F2F66A800F89830 /* lossless_enc_neon.c in Sources */, 321E60C81F38E91700405457 /* UIImage+ForceDecode.m in Sources */, - 80377C721F2F666400F89830 /* random_utils.c in Sources */, - 80377ECB1F2F66D500F89830 /* frame_dec.c in Sources */, - 80377C6A1F2F666400F89830 /* huffman_encode_utils.c in Sources */, 328BB6CB2082581100760D6C /* SDDiskCache.m in Sources */, - 323F8B481F38EF770092B609 /* analysis_enc.c in Sources */, - 80377DFE1F2F66A800F89830 /* dec_msa.c in Sources */, 325312D2200F09910046BF1E /* SDWebImageTransition.m in Sources */, - 323F8BBE1F38EF770092B609 /* predictor_enc.c in Sources */, - 80377E261F2F66A800F89830 /* rescaler_sse2.c in Sources */, - 323F8C181F38EF770092B609 /* muxinternal.c in Sources */, 32D1222E2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, - 80377C741F2F666400F89830 /* rescaler_utils.c in Sources */, 431BB6B11D06D2C1006A3455 /* UIView+WebCacheOperation.m in Sources */, - 80377DF01F2F66A800F89830 /* alpha_processing_sse41.c in Sources */, - 80377ECC1F2F66D500F89830 /* idec_dec.c in Sources */, - 323F8B7E1F38EF770092B609 /* frame_enc.c in Sources */, 321B37972083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, - 80377E171F2F66A800F89830 /* lossless_enc_sse41.c in Sources */, 32484761201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, - 323F8B901F38EF770092B609 /* iterator_enc.c in Sources */, 32484773201775F600AF9E5A /* SDAnimatedImage.m in Sources */, - 80377C611F2F666400F89830 /* bit_reader_utils.c in Sources */, 3248477F201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, - 323F8BAC1F38EF770092B609 /* picture_psnr_enc.c in Sources */, - 323F8C0C1F38EF770092B609 /* muxedit.c in Sources */, 32C0FDEB2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, - 80377DEE1F2F66A800F89830 /* alpha_processing_neon.c in Sources */, - 43C892A41D9D6DDD0022038D /* demux.c in Sources */, 3237F9EA20161AE000A88143 /* NSImage+Compatibility.m in Sources */, - 80377E251F2F66A800F89830 /* rescaler_neon.c in Sources */, 32B9B541206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, 32F7C0792030114C00873181 /* SDImageTransformer.m in Sources */, - 80377E241F2F66A800F89830 /* rescaler_msa.c in Sources */, - 80377E2D1F2F66A800F89830 /* yuv_mips_dsp_r2.c in Sources */, 431BB6B91D06D2C1006A3455 /* UIButton+WebCache.m in Sources */, - 323F8BC41F38EF770092B609 /* quant_enc.c in Sources */, - 323F8BB81F38EF770092B609 /* picture_tools_enc.c in Sources */, - 80377E301F2F66A800F89830 /* yuv.c in Sources */, 43A9186F1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, - 323F8BD61F38EF770092B609 /* tree_enc.c in Sources */, 327054DE206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, - 80377DFD1F2F66A800F89830 /* dec_mips32.c in Sources */, - 323F8BCA1F38EF770092B609 /* syntax_enc.c in Sources */, 328BB6D72082581100760D6C /* SDMemoryCache.m in Sources */, - 80377E2B1F2F66A800F89830 /* upsampling_sse2.c in Sources */, 324DF4BE200A14DC008A84CC /* SDWebImageDefine.m in Sources */, - 80377E011F2F66A800F89830 /* dec_sse41.c in Sources */, - 80377E141F2F66A800F89830 /* lossless_enc_msa.c in Sources */, - 323F8BA01F38EF770092B609 /* picture_csp_enc.c in Sources */, - 80377C701F2F666400F89830 /* quant_levels_utils.c in Sources */, 328BB6B42081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, 431BB6BD1D06D2C1006A3455 /* UIImage+GIF.m in Sources */, 32CF1C111FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, - 323F8B5A1F38EF770092B609 /* config_enc.c in Sources */, - 80377E061F2F66A800F89830 /* enc_mips32.c in Sources */, - 80377E121F2F66A800F89830 /* lossless_enc_mips_dsp_r2.c in Sources */, - 323F8BD01F38EF770092B609 /* token_enc.c in Sources */, - 80377EC71F2F66D500F89830 /* alpha_dec.c in Sources */, - 323F8B6C1F38EF770092B609 /* delta_palettization_enc.c in Sources */, - 80377C681F2F666400F89830 /* filters_utils.c in Sources */, 321E60AC1F38E8F600405457 /* SDImageGIFCoder.m in Sources */, - 80377E291F2F66A800F89830 /* upsampling_msa.c in Sources */, - 80377E181F2F66A800F89830 /* lossless_enc.c in Sources */, 431BB6C01D06D2C1006A3455 /* SDImageCache.m in Sources */, - 80377C651F2F666400F89830 /* color_cache_utils.c in Sources */, 431BB6C41D06D2C1006A3455 /* UIImage+MultiFormat.m in Sources */, - 80377DF21F2F66A800F89830 /* argb_mips_dsp_r2.c in Sources */, - 80377E2C1F2F66A800F89830 /* upsampling.c in Sources */, - 80377DF41F2F66A800F89830 /* argb.c in Sources */, - 80377DF71F2F66A800F89830 /* cost_mips32.c in Sources */, - 32FDE89F20888726008D7530 /* SDImageWebPCoder.m in Sources */, - 323F8BF41F38EF770092B609 /* anim_encode.c in Sources */, - 80377C6E1F2F666400F89830 /* quant_levels_dec_utils.c in Sources */, - 80377EC91F2F66D500F89830 /* buffer_dec.c in Sources */, - 80377C6C1F2F666400F89830 /* huffman_utils.c in Sources */, 32F7C0822030719600873181 /* UIImage+Transform.m in Sources */, 321B378B2083290E00C0EA77 /* SDImageLoader.m in Sources */, - 80377E161F2F66A800F89830 /* lossless_enc_sse2.c in Sources */, 431BB6C71D06D2C1006A3455 /* UIImageView+HighlightedWebCache.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3633,167 +1668,53 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 80377E591F2F66A800F89830 /* lossless_enc_msa.c in Sources */, - 80377E511F2F66A800F89830 /* filters_mips_dsp_r2.c in Sources */, - 80377E371F2F66A800F89830 /* argb_mips_dsp_r2.c in Sources */, - 80377E471F2F66A800F89830 /* dec.c in Sources */, - 80377C921F2F666400F89830 /* utils.c in Sources */, 4397D27E1D0DDD8C00BB2784 /* UIImage+GIF.m in Sources */, 321E60911F38E8C800405457 /* SDImageCoder.m in Sources */, - 80377C8A1F2F666400F89830 /* quant_levels_utils.c in Sources */, 4397D2F71D0DE2DF00BB2784 /* NSImage+Compatibility.m in Sources */, - 80377E751F2F66A800F89830 /* yuv.c in Sources */, - 43C892A01D9D6DDA0022038D /* anim_decode.c in Sources */, - 80377E4A1F2F66A800F89830 /* enc_mips_dsp_r2.c in Sources */, - 80377E411F2F66A800F89830 /* dec_mips_dsp_r2.c in Sources */, - 80377EDC1F2F66D500F89830 /* idec_dec.c in Sources */, - 80377E501F2F66A800F89830 /* enc.c in Sources */, - 80377E721F2F66A800F89830 /* yuv_mips_dsp_r2.c in Sources */, - 323F8BA71F38EF770092B609 /* picture_enc.c in Sources */, - 80377E601F2F66A800F89830 /* lossless_neon.c in Sources */, - 80377E461F2F66A800F89830 /* dec_sse41.c in Sources */, - 43C892A51D9D6DDE0022038D /* demux.c in Sources */, - 80377E3E1F2F66A800F89830 /* cost.c in Sources */, - 323F8BEF1F38EF770092B609 /* webp_enc.c in Sources */, - 323F8BA11F38EF770092B609 /* picture_csp_enc.c in Sources */, 32FDE87F2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */, - 323F8C1F1F38EF770092B609 /* muxread.c in Sources */, 328BB6CC2082581100760D6C /* SDDiskCache.m in Sources */, - 323F8C0D1F38EF770092B609 /* muxedit.c in Sources */, - 323F8B491F38EF770092B609 /* analysis_enc.c in Sources */, 320CAE202086F50500CFFC80 /* SDWebImageError.m in Sources */, - 80377E6E1F2F66A800F89830 /* upsampling_msa.c in Sources */, - 323F8B911F38EF770092B609 /* iterator_enc.c in Sources */, 3290FA0F1FA478AF0047D20C /* SDImageFrame.m in Sources */, - 80377EE01F2F66D500F89830 /* vp8_dec.c in Sources */, 32CF1C121FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, 32B9B542206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, - 80377E521F2F66A800F89830 /* filters_msa.c in Sources */, 329A18641FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, - 80377C821F2F666400F89830 /* filters_utils.c in Sources */, 324DF4BF200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 4397D28C1D0DDD8C00BB2784 /* UIImageView+WebCache.m in Sources */, - 80377E581F2F66A800F89830 /* lossless_enc_mips32.c in Sources */, 4397D28F1D0DDD8C00BB2784 /* SDWebImageDownloaderOperation.m in Sources */, - 323F8BB91F38EF770092B609 /* picture_tools_enc.c in Sources */, - 32FDE8A020888726008D7530 /* SDImageWebPCoder.m in Sources */, - 80377E451F2F66A800F89830 /* dec_sse2.c in Sources */, - 80377E3F1F2F66A800F89830 /* cpu.c in Sources */, - 80377E4C1F2F66A800F89830 /* enc_msa.c in Sources */, - 80377E4E1F2F66A800F89830 /* enc_sse2.c in Sources */, - 80377E6C1F2F66A800F89830 /* rescaler.c in Sources */, 32484762201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 328BB6D82082581100760D6C /* SDMemoryCache.m in Sources */, - 80377EE31F2F66D500F89830 /* vp8l_dec.c in Sources */, 328BB6B52081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, - 80377ED71F2F66D500F89830 /* alpha_dec.c in Sources */, - 323F8B7F1F38EF770092B609 /* frame_enc.c in Sources */, - 80377E681F2F66A800F89830 /* rescaler_mips32.c in Sources */, - 80377E621F2F66A800F89830 /* lossless.c in Sources */, - 80377E5D1F2F66A800F89830 /* lossless_enc.c in Sources */, - 80377EDF1F2F66D500F89830 /* tree_dec.c in Sources */, - 80377C7D1F2F666400F89830 /* bit_writer_utils.c in Sources */, - 80377C7B1F2F666400F89830 /* bit_reader_utils.c in Sources */, - 323F8B6D1F38EF770092B609 /* delta_palettization_enc.c in Sources */, 321E60C91F38E91700405457 /* UIImage+ForceDecode.m in Sources */, - 80377E551F2F66A800F89830 /* filters.c in Sources */, - 80377E731F2F66A800F89830 /* yuv_mips32.c in Sources */, 32D1222F2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, 4397D2921D0DDD8C00BB2784 /* SDWebImagePrefetcher.m in Sources */, - 323F8BBF1F38EF770092B609 /* predictor_enc.c in Sources */, - 32FDE88E20888726008D7530 /* UIImage+WebP.m in Sources */, 807A12331F89636300EC2A9B /* SDImageCodersManager.m in Sources */, - 323F8BD11F38EF770092B609 /* token_enc.c in Sources */, - 323F8B4F1F38EF770092B609 /* backward_references_enc.c in Sources */, - 80377E4D1F2F66A800F89830 /* enc_neon.c in Sources */, 4397D2961D0DDD8C00BB2784 /* UIImage+MultiFormat.m in Sources */, - 323F8BF51F38EF770092B609 /* anim_encode.c in Sources */, - 80377E381F2F66A800F89830 /* argb_sse2.c in Sources */, - 323F8B9B1F38EF770092B609 /* near_lossless_enc.c in Sources */, 32F21B5C20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 32D122292080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, - 80377E3B1F2F66A800F89830 /* cost_mips_dsp_r2.c in Sources */, 321B378C2083290E00C0EA77 /* SDImageLoader.m in Sources */, 4397D29B1D0DDD8C00BB2784 /* SDWebImageDownloader.m in Sources */, - 80377E711F2F66A800F89830 /* upsampling.c in Sources */, 328BB6A72081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 4397D29C1D0DDD8C00BB2784 /* NSData+ImageContentType.m in Sources */, - 323F8BB31F38EF770092B609 /* picture_rescale_enc.c in Sources */, - 80377E6A1F2F66A800F89830 /* rescaler_neon.c in Sources */, - 80377C841F2F666400F89830 /* huffman_encode_utils.c in Sources */, - 80377E491F2F66A800F89830 /* enc_avx2.c in Sources */, - 80377E531F2F66A800F89830 /* filters_neon.c in Sources */, - 323F8B431F38EF770092B609 /* alpha_enc.c in Sources */, - 323F8C191F38EF770092B609 /* muxinternal.c in Sources */, - 80377E5F1F2F66A800F89830 /* lossless_msa.c in Sources */, - 80377C8C1F2F666400F89830 /* random_utils.c in Sources */, - 323F8BAD1F38EF770092B609 /* picture_psnr_enc.c in Sources */, - 323F8BC51F38EF770092B609 /* quant_enc.c in Sources */, 321DB3622011D4D70015D2CB /* NSButton+WebCache.m in Sources */, - 80377C7F1F2F666400F89830 /* color_cache_utils.c in Sources */, - 80377E331F2F66A800F89830 /* alpha_processing_neon.c in Sources */, - 80377E401F2F66A800F89830 /* dec_clip_tables.c in Sources */, - 80377C901F2F666400F89830 /* thread_utils.c in Sources */, - 80377E441F2F66A800F89830 /* dec_neon.c in Sources */, - 80377E741F2F66A800F89830 /* yuv_sse2.c in Sources */, - 80377E431F2F66A800F89830 /* dec_msa.c in Sources */, - 80377E6B1F2F66A800F89830 /* rescaler_sse2.c in Sources */, - 80377E671F2F66A800F89830 /* rescaler_mips_dsp_r2.c in Sources */, - 80377E541F2F66A800F89830 /* filters_sse2.c in Sources */, - 80377EDB1F2F66D500F89830 /* frame_dec.c in Sources */, - 80377C861F2F666400F89830 /* huffman_utils.c in Sources */, - 323F8BD71F38EF770092B609 /* tree_enc.c in Sources */, - 80377E571F2F66A800F89830 /* lossless_enc_mips_dsp_r2.c in Sources */, - 80377E5B1F2F66A800F89830 /* lossless_enc_sse2.c in Sources */, - 80377ED91F2F66D500F89830 /* buffer_dec.c in Sources */, 4397D2A11D0DDD8C00BB2784 /* SDWebImageManager.m in Sources */, - 323F8BCB1F38EF770092B609 /* syntax_enc.c in Sources */, 321E60AD1F38E8F600405457 /* SDImageGIFCoder.m in Sources */, 327054DF206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, - 80377E341F2F66A800F89830 /* alpha_processing_sse2.c in Sources */, 4397D2A61D0DDD8C00BB2784 /* SDWebImageCompat.m in Sources */, - 80377E6F1F2F66A800F89830 /* upsampling_neon.c in Sources */, 4397D2A81D0DDD8C00BB2784 /* UIButton+WebCache.m in Sources */, 320224BC203979BA00E9F285 /* SDAnimatedImageRep.m in Sources */, - 80377C8E1F2F666400F89830 /* rescaler_utils.c in Sources */, - 80377E5C1F2F66A800F89830 /* lossless_enc_sse41.c in Sources */, - 323F8BE31F38EF770092B609 /* vp8l_enc.c in Sources */, - 80377C881F2F666400F89830 /* quant_levels_dec_utils.c in Sources */, - 80377E5A1F2F66A800F89830 /* lossless_enc_neon.c in Sources */, - 80377E6D1F2F66A800F89830 /* upsampling_mips_dsp_r2.c in Sources */, - 80377E321F2F66A800F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, - 323F8B611F38EF770092B609 /* cost_enc.c in Sources */, - 80377EDE1F2F66D500F89830 /* quant_dec.c in Sources */, 321E609F1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, - 323F8B5B1F38EF770092B609 /* config_enc.c in Sources */, - 80377E361F2F66A800F89830 /* alpha_processing.c in Sources */, - 80377E351F2F66A800F89830 /* alpha_processing_sse41.c in Sources */, 32484780201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, - 323F8B791F38EF770092B609 /* filter_enc.c in Sources */, - 80377EDD1F2F66D500F89830 /* io_dec.c in Sources */, 43A918701D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, - 80377E4B1F2F66A800F89830 /* enc_mips32.c in Sources */, 4397D2AB1D0DDD8C00BB2784 /* UIView+WebCacheOperation.m in Sources */, 325312D3200F09910046BF1E /* SDWebImageTransition.m in Sources */, - 80377E391F2F66A800F89830 /* argb.c in Sources */, 4369C2831D9807EC007E863A /* UIView+WebCache.m in Sources */, - 80377E611F2F66A800F89830 /* lossless_sse2.c in Sources */, - 80377E691F2F66A800F89830 /* rescaler_msa.c in Sources */, 32C0FDEC2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, - 80377E5E1F2F66A800F89830 /* lossless_mips_dsp_r2.c in Sources */, - 80377E3D1F2F66A800F89830 /* cost_sse2.c in Sources */, 32F7C0832030719600873181 /* UIImage+Transform.m in Sources */, - 80377E3C1F2F66A800F89830 /* cost_mips32.c in Sources */, - 80377E421F2F66A800F89830 /* dec_mips32.c in Sources */, 32484774201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 4397D2AE1D0DDD8C00BB2784 /* UIImageView+HighlightedWebCache.m in Sources */, - 323F8B851F38EF770092B609 /* histogram_enc.c in Sources */, - 80377EE51F2F66D500F89830 /* webp_dec.c in Sources */, 4397D2B01D0DDD8C00BB2784 /* SDImageCache.m in Sources */, 321B37982083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, 32F7C07A2030114C00873181 /* SDImageTransformer.m in Sources */, - 80377E4F1F2F66A800F89830 /* enc_sse41.c in Sources */, - 80377E701F2F66A800F89830 /* upsampling_sse2.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3801,166 +1722,52 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 80377D8E1F2F66A700F89830 /* lossless_enc.c in Sources */, - 32FDE88B20888726008D7530 /* UIImage+WebP.m in Sources */, - 323F8BBC1F38EF770092B609 /* predictor_enc.c in Sources */, 3290FA0C1FA478AF0047D20C /* SDImageFrame.m in Sources */, - 80377D781F2F66A700F89830 /* dec.c in Sources */, - 80377DA21F2F66A700F89830 /* upsampling.c in Sources */, - 80377C401F2F666300F89830 /* rescaler_utils.c in Sources */, 321E60C61F38E91700405457 /* UIImage+ForceDecode.m in Sources */, - 323F8BB61F38EF770092B609 /* picture_tools_enc.c in Sources */, - 80377DA51F2F66A700F89830 /* yuv_sse2.c in Sources */, - 323F8B8E1F38EF770092B609 /* iterator_enc.c in Sources */, - 80377D741F2F66A700F89830 /* dec_msa.c in Sources */, - 80377D661F2F66A700F89830 /* alpha_processing_sse41.c in Sources */, - 323F8BE01F38EF770092B609 /* vp8l_enc.c in Sources */, - 80377D751F2F66A700F89830 /* dec_neon.c in Sources */, - 80377C421F2F666300F89830 /* thread_utils.c in Sources */, 328BB6A42081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 4A2CAE2E1AB4BB7500B6BC39 /* UIImage+GIF.m in Sources */, - 80377D7A1F2F66A700F89830 /* enc_avx2.c in Sources */, - 80377D821F2F66A700F89830 /* filters_mips_dsp_r2.c in Sources */, - 80377D7B1F2F66A700F89830 /* enc_mips_dsp_r2.c in Sources */, - 323F8BC81F38EF770092B609 /* syntax_enc.c in Sources */, - 80377D641F2F66A700F89830 /* alpha_processing_neon.c in Sources */, - 80377C361F2F666300F89830 /* huffman_encode_utils.c in Sources */, - 80377D721F2F66A700F89830 /* dec_mips_dsp_r2.c in Sources */, 320CAE1D2086F50500CFFC80 /* SDWebImageError.m in Sources */, - 80377D7E1F2F66A700F89830 /* enc_neon.c in Sources */, - 80377DA01F2F66A700F89830 /* upsampling_neon.c in Sources */, - 80377D691F2F66A700F89830 /* argb_sse2.c in Sources */, 32CF1C0F1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, - 80377D6A1F2F66A700F89830 /* argb.c in Sources */, - 323F8B7C1F38EF770092B609 /* frame_enc.c in Sources */, 328BB6D52082581100760D6C /* SDMemoryCache.m in Sources */, - 80377EAB1F2F66D400F89830 /* frame_dec.c in Sources */, 32F7C0772030114C00873181 /* SDImageTransformer.m in Sources */, - 43C8929D1D9D6DD90022038D /* anim_decode.c in Sources */, - 323F8B6A1F38EF770092B609 /* delta_palettization_enc.c in Sources */, - 323F8B5E1F38EF770092B609 /* cost_enc.c in Sources */, - 80377D8A1F2F66A700F89830 /* lossless_enc_msa.c in Sources */, - 80377EA91F2F66D400F89830 /* buffer_dec.c in Sources */, - 80377C341F2F666300F89830 /* filters_utils.c in Sources */, - 80377D901F2F66A700F89830 /* lossless_msa.c in Sources */, - 80377DA61F2F66A700F89830 /* yuv.c in Sources */, 3237F9E820161AE000A88143 /* NSImage+Compatibility.m in Sources */, 32C0FDE92013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 32F21B5920788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, - 80377D811F2F66A700F89830 /* enc.c in Sources */, - 80377EA71F2F66D400F89830 /* alpha_dec.c in Sources */, - 80377D8F1F2F66A700F89830 /* lossless_mips_dsp_r2.c in Sources */, - 80377C3E1F2F666300F89830 /* random_utils.c in Sources */, - 323F8B761F38EF770092B609 /* filter_enc.c in Sources */, - 80377D981F2F66A700F89830 /* rescaler_mips_dsp_r2.c in Sources */, - 323F8B4C1F38EF770092B609 /* backward_references_enc.c in Sources */, - 80377D881F2F66A700F89830 /* lossless_enc_mips_dsp_r2.c in Sources */, - 323F8BF21F38EF770092B609 /* anim_encode.c in Sources */, - 80377D921F2F66A700F89830 /* lossless_sse2.c in Sources */, - 80377D631F2F66A700F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, - 80377D6C1F2F66A700F89830 /* cost_mips_dsp_r2.c in Sources */, 321B37952083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, 4A2CAE361AB4BB7500B6BC39 /* UIImageView+WebCache.m in Sources */, - 323F8B581F38EF770092B609 /* config_enc.c in Sources */, - 43C892A21D9D6DDD0022038D /* demux.c in Sources */, - 80377DA41F2F66A700F89830 /* yuv_mips32.c in Sources */, 4A2CAE1E1AB4BB6800B6BC39 /* SDWebImageDownloaderOperation.m in Sources */, - 80377EAD1F2F66D400F89830 /* io_dec.c in Sources */, - 80377EAC1F2F66D400F89830 /* idec_dec.c in Sources */, 32F7C0802030719600873181 /* UIImage+Transform.m in Sources */, - 323F8B981F38EF770092B609 /* near_lossless_enc.c in Sources */, - 80377D6F1F2F66A700F89830 /* cost.c in Sources */, - 80377EB31F2F66D400F89830 /* vp8l_dec.c in Sources */, 327054DC206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, 325312D0200F09910046BF1E /* SDWebImageTransition.m in Sources */, 321E609C1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, - 323F8B9E1F38EF770092B609 /* picture_csp_enc.c in Sources */, - 80377D9E1F2F66A700F89830 /* upsampling_mips_dsp_r2.c in Sources */, - 80377DA31F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */, - 80377EAF1F2F66D400F89830 /* tree_dec.c in Sources */, 4A2CAE261AB4BB7000B6BC39 /* SDWebImagePrefetcher.m in Sources */, 328BB6C92082581100760D6C /* SDDiskCache.m in Sources */, 3248475F201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, - 80377C441F2F666300F89830 /* utils.c in Sources */, - 80377D8D1F2F66A700F89830 /* lossless_enc_sse41.c in Sources */, - 80377EAE1F2F66D400F89830 /* quant_dec.c in Sources */, 32D1222C2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, - 80377D6E1F2F66A700F89830 /* cost_sse2.c in Sources */, - 80377D991F2F66A700F89830 /* rescaler_mips32.c in Sources */, 32B9B53F206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, - 323F8C0A1F38EF770092B609 /* muxedit.c in Sources */, - 80377D851F2F66A700F89830 /* filters_sse2.c in Sources */, - 80377D711F2F66A700F89830 /* dec_clip_tables.c in Sources */, 43A9186D1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, 3248477D201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, - 80377D7C1F2F66A700F89830 /* enc_mips32.c in Sources */, - 80377D771F2F66A700F89830 /* dec_sse41.c in Sources */, - 80377D891F2F66A700F89830 /* lossless_enc_mips32.c in Sources */, - 80377D861F2F66A700F89830 /* filters.c in Sources */, 321E60AA1F38E8F600405457 /* SDImageGIFCoder.m in Sources */, - 323F8BD41F38EF770092B609 /* tree_enc.c in Sources */, - 80377D651F2F66A700F89830 /* alpha_processing_sse2.c in Sources */, - 323F8B821F38EF770092B609 /* histogram_enc.c in Sources */, 321E608E1F38E8C800405457 /* SDImageCoder.m in Sources */, 4A2CAE301AB4BB7500B6BC39 /* UIImage+MultiFormat.m in Sources */, - 323F8B401F38EF770092B609 /* alpha_enc.c in Sources */, - 80377C2D1F2F666300F89830 /* bit_reader_utils.c in Sources */, - 323F8BC21F38EF770092B609 /* quant_enc.c in Sources */, - 80377D761F2F66A700F89830 /* dec_sse2.c in Sources */, 4A2CAE1C1AB4BB6800B6BC39 /* SDWebImageDownloader.m in Sources */, 4A2CAE2A1AB4BB7500B6BC39 /* NSData+ImageContentType.m in Sources */, 32FDE87D2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */, - 80377D9A1F2F66A700F89830 /* rescaler_msa.c in Sources */, - 80377D9F1F2F66A700F89830 /* upsampling_msa.c in Sources */, - 80377D7D1F2F66A700F89830 /* enc_msa.c in Sources */, - 80377D841F2F66A700F89830 /* filters_neon.c in Sources */, - 80377D801F2F66A700F89830 /* enc_sse41.c in Sources */, 4A2CAE221AB4BB7000B6BC39 /* SDWebImageManager.m in Sources */, 4A2CAE191AB4BB6400B6BC39 /* SDWebImageCompat.m in Sources */, - 80377DA11F2F66A700F89830 /* upsampling_sse2.c in Sources */, - 323F8BCE1F38EF770092B609 /* token_enc.c in Sources */, 321B37892083290E00C0EA77 /* SDImageLoader.m in Sources */, 32484771201775F600AF9E5A /* SDAnimatedImage.m in Sources */, - 80377C3C1F2F666300F89830 /* quant_levels_utils.c in Sources */, - 323F8C1C1F38EF770092B609 /* muxread.c in Sources */, 807A12301F89636300EC2A9B /* SDImageCodersManager.m in Sources */, - 80377C2F1F2F666300F89830 /* bit_writer_utils.c in Sources */, - 323F8B461F38EF770092B609 /* analysis_enc.c in Sources */, - 80377D8C1F2F66A700F89830 /* lossless_enc_sse2.c in Sources */, 4A2CAE2C1AB4BB7500B6BC39 /* UIButton+WebCache.m in Sources */, - 80377EB51F2F66D400F89830 /* webp_dec.c in Sources */, 32D122262080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, - 80377D701F2F66A700F89830 /* cpu.c in Sources */, - 80377D911F2F66A700F89830 /* lossless_neon.c in Sources */, - 80377EB01F2F66D400F89830 /* vp8_dec.c in Sources */, - 80377C381F2F666300F89830 /* huffman_utils.c in Sources */, - 32FDE89D20888726008D7530 /* SDImageWebPCoder.m in Sources */, - 80377C3A1F2F666300F89830 /* quant_levels_dec_utils.c in Sources */, 324DF4BC200A14DC008A84CC /* SDWebImageDefine.m in Sources */, - 80377D931F2F66A700F89830 /* lossless.c in Sources */, - 80377D9C1F2F66A700F89830 /* rescaler_sse2.c in Sources */, - 80377D671F2F66A700F89830 /* alpha_processing.c in Sources */, - 80377D9B1F2F66A700F89830 /* rescaler_neon.c in Sources */, 4A2CAE381AB4BB7500B6BC39 /* UIView+WebCacheOperation.m in Sources */, - 80377C311F2F666300F89830 /* color_cache_utils.c in Sources */, - 323F8BEC1F38EF770092B609 /* webp_enc.c in Sources */, - 80377D731F2F66A700F89830 /* dec_mips32.c in Sources */, - 80377D7F1F2F66A700F89830 /* enc_sse2.c in Sources */, - 323F8C161F38EF770092B609 /* muxinternal.c in Sources */, - 323F8BB01F38EF770092B609 /* picture_rescale_enc.c in Sources */, 32EB6D8E206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, - 80377D6D1F2F66A700F89830 /* cost_mips32.c in Sources */, - 80377D831F2F66A700F89830 /* filters_msa.c in Sources */, 4A2CAE341AB4BB7500B6BC39 /* UIImageView+HighlightedWebCache.m in Sources */, 4A2CAE201AB4BB6C00B6BC39 /* SDImageCache.m in Sources */, 4369C2801D9807EC007E863A /* UIView+WebCache.m in Sources */, - 80377D8B1F2F66A700F89830 /* lossless_enc_neon.c in Sources */, 329A18611FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, - 80377D9D1F2F66A700F89830 /* rescaler.c in Sources */, 328BB6B22081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, - 80377D681F2F66A700F89830 /* argb_mips_dsp_r2.c in Sources */, - 323F8BAA1F38EF770092B609 /* picture_psnr_enc.c in Sources */, - 323F8BA41F38EF770092B609 /* picture_enc.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3968,166 +1775,52 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 80377D041F2F66A100F89830 /* lossless_enc.c in Sources */, - 32FDE88920888726008D7530 /* UIImage+WebP.m in Sources */, - 323F8BBA1F38EF770092B609 /* predictor_enc.c in Sources */, 3290FA0A1FA478AF0047D20C /* SDImageFrame.m in Sources */, - 80377CEE1F2F66A100F89830 /* dec.c in Sources */, - 80377D181F2F66A100F89830 /* upsampling.c in Sources */, - 80377C0C1F2F665300F89830 /* rescaler_utils.c in Sources */, 321E60C41F38E91700405457 /* UIImage+ForceDecode.m in Sources */, - 323F8BB41F38EF770092B609 /* picture_tools_enc.c in Sources */, - 80377D1B1F2F66A100F89830 /* yuv_sse2.c in Sources */, - 323F8B8C1F38EF770092B609 /* iterator_enc.c in Sources */, - 80377CEA1F2F66A100F89830 /* dec_msa.c in Sources */, - 80377CDC1F2F66A100F89830 /* alpha_processing_sse41.c in Sources */, - 323F8BDE1F38EF770092B609 /* vp8l_enc.c in Sources */, - 80377CEB1F2F66A100F89830 /* dec_neon.c in Sources */, - 80377C0E1F2F665300F89830 /* thread_utils.c in Sources */, 328BB6A22081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 53761309155AD0D5005750A4 /* SDImageCache.m in Sources */, - 80377CF01F2F66A100F89830 /* enc_avx2.c in Sources */, - 80377CF81F2F66A100F89830 /* filters_mips_dsp_r2.c in Sources */, - 80377CF11F2F66A100F89830 /* enc_mips_dsp_r2.c in Sources */, - 323F8BC61F38EF770092B609 /* syntax_enc.c in Sources */, - 80377CDA1F2F66A100F89830 /* alpha_processing_neon.c in Sources */, - 80377C021F2F665300F89830 /* huffman_encode_utils.c in Sources */, - 80377CE81F2F66A100F89830 /* dec_mips_dsp_r2.c in Sources */, 320CAE1B2086F50500CFFC80 /* SDWebImageError.m in Sources */, - 80377CF41F2F66A100F89830 /* enc_neon.c in Sources */, - 80377D161F2F66A100F89830 /* upsampling_neon.c in Sources */, - 80377CDF1F2F66A100F89830 /* argb_sse2.c in Sources */, - 80377CE01F2F66A100F89830 /* argb.c in Sources */, 32CF1C0D1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, - 323F8B7A1F38EF770092B609 /* frame_enc.c in Sources */, - 80377E8B1F2F66D000F89830 /* frame_dec.c in Sources */, 328BB6D32082581100760D6C /* SDMemoryCache.m in Sources */, - 43C8929A1D9D6DD70022038D /* anim_decode.c in Sources */, 32F7C0752030114C00873181 /* SDImageTransformer.m in Sources */, - 323F8B681F38EF770092B609 /* delta_palettization_enc.c in Sources */, - 323F8B5C1F38EF770092B609 /* cost_enc.c in Sources */, - 80377D001F2F66A100F89830 /* lossless_enc_msa.c in Sources */, - 80377E891F2F66D000F89830 /* buffer_dec.c in Sources */, - 80377C001F2F665300F89830 /* filters_utils.c in Sources */, - 80377D061F2F66A100F89830 /* lossless_msa.c in Sources */, - 80377D1C1F2F66A100F89830 /* yuv.c in Sources */, - 80377CF71F2F66A100F89830 /* enc.c in Sources */, 3237F9EB20161AE000A88143 /* NSImage+Compatibility.m in Sources */, 32C0FDE72013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 32F21B5720788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, - 80377E871F2F66D000F89830 /* alpha_dec.c in Sources */, - 80377D051F2F66A100F89830 /* lossless_mips_dsp_r2.c in Sources */, - 80377C0A1F2F665300F89830 /* random_utils.c in Sources */, - 323F8B741F38EF770092B609 /* filter_enc.c in Sources */, - 80377D0E1F2F66A100F89830 /* rescaler_mips_dsp_r2.c in Sources */, - 323F8B4A1F38EF770092B609 /* backward_references_enc.c in Sources */, - 80377CFE1F2F66A100F89830 /* lossless_enc_mips_dsp_r2.c in Sources */, - 323F8BF01F38EF770092B609 /* anim_encode.c in Sources */, - 80377D081F2F66A100F89830 /* lossless_sse2.c in Sources */, - 80377CD91F2F66A100F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, - 80377CE21F2F66A100F89830 /* cost_mips_dsp_r2.c in Sources */, 5376130B155AD0D5005750A4 /* SDWebImageDownloader.m in Sources */, 321B37932083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, - 323F8B561F38EF770092B609 /* config_enc.c in Sources */, - 43C8929B1D9D6DD70022038D /* demux.c in Sources */, - 80377D1A1F2F66A100F89830 /* yuv_mips32.c in Sources */, - 80377E8D1F2F66D000F89830 /* io_dec.c in Sources */, - 80377E8C1F2F66D000F89830 /* idec_dec.c in Sources */, - 323F8B961F38EF770092B609 /* near_lossless_enc.c in Sources */, 32F7C07E2030719600873181 /* UIImage+Transform.m in Sources */, - 80377CE51F2F66A100F89830 /* cost.c in Sources */, - 80377E931F2F66D000F89830 /* vp8l_dec.c in Sources */, 321E609A1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, 327054DA206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, 325312CE200F09910046BF1E /* SDWebImageTransition.m in Sources */, - 323F8B9C1F38EF770092B609 /* picture_csp_enc.c in Sources */, - 80377D141F2F66A100F89830 /* upsampling_mips_dsp_r2.c in Sources */, - 80377D191F2F66A100F89830 /* yuv_mips_dsp_r2.c in Sources */, - 80377E8F1F2F66D000F89830 /* tree_dec.c in Sources */, 5376130C155AD0D5005750A4 /* SDWebImageManager.m in Sources */, 5376130D155AD0D5005750A4 /* SDWebImagePrefetcher.m in Sources */, - 80377C101F2F665300F89830 /* utils.c in Sources */, 328BB6C72082581100760D6C /* SDDiskCache.m in Sources */, 3248475D201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, - 80377D031F2F66A100F89830 /* lossless_enc_sse41.c in Sources */, - 80377E8E1F2F66D000F89830 /* quant_dec.c in Sources */, - 80377CE41F2F66A100F89830 /* cost_sse2.c in Sources */, 32D1222A2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, - 80377D0F1F2F66A100F89830 /* rescaler_mips32.c in Sources */, - 323F8C081F38EF770092B609 /* muxedit.c in Sources */, 32B9B53D206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, - 80377CFB1F2F66A100F89830 /* filters_sse2.c in Sources */, - 80377CE71F2F66A100F89830 /* dec_clip_tables.c in Sources */, 43A9186B1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, - 80377CF21F2F66A100F89830 /* enc_mips32.c in Sources */, 3248477B201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, - 80377CED1F2F66A100F89830 /* dec_sse41.c in Sources */, - 80377CFF1F2F66A100F89830 /* lossless_enc_mips32.c in Sources */, - 80377CFC1F2F66A100F89830 /* filters.c in Sources */, 321E60A81F38E8F600405457 /* SDImageGIFCoder.m in Sources */, - 323F8BD21F38EF770092B609 /* tree_enc.c in Sources */, - 80377CDB1F2F66A100F89830 /* alpha_processing_sse2.c in Sources */, - 323F8B801F38EF770092B609 /* histogram_enc.c in Sources */, 321E608C1F38E8C800405457 /* SDImageCoder.m in Sources */, 5376130E155AD0D5005750A4 /* UIButton+WebCache.m in Sources */, - 323F8B3E1F38EF770092B609 /* alpha_enc.c in Sources */, - 80377BF91F2F665300F89830 /* bit_reader_utils.c in Sources */, - 323F8BC01F38EF770092B609 /* quant_enc.c in Sources */, - 80377CEC1F2F66A100F89830 /* dec_sse2.c in Sources */, 5376130F155AD0D5005750A4 /* UIImageView+WebCache.m in Sources */, 530E49EC16464C84002868E7 /* SDWebImageDownloaderOperation.m in Sources */, 32FDE87C2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */, - 80377D101F2F66A100F89830 /* rescaler_msa.c in Sources */, - 80377D151F2F66A100F89830 /* upsampling_msa.c in Sources */, - 80377CF31F2F66A100F89830 /* enc_msa.c in Sources */, - 80377CFA1F2F66A100F89830 /* filters_neon.c in Sources */, - 80377CF61F2F66A100F89830 /* enc_sse41.c in Sources */, 53406750167780C40042B59E /* SDWebImageCompat.m in Sources */, - 80377D171F2F66A100F89830 /* upsampling_sse2.c in Sources */, - 323F8BCC1F38EF770092B609 /* token_enc.c in Sources */, - 80377C081F2F665300F89830 /* quant_levels_utils.c in Sources */, 321B37872083290E00C0EA77 /* SDImageLoader.m in Sources */, 3248476F201775F600AF9E5A /* SDAnimatedImage.m in Sources */, - 323F8C1A1F38EF770092B609 /* muxread.c in Sources */, 807A122E1F89636300EC2A9B /* SDImageCodersManager.m in Sources */, - 80377BFB1F2F665300F89830 /* bit_writer_utils.c in Sources */, - 323F8B441F38EF770092B609 /* analysis_enc.c in Sources */, - 80377D021F2F66A100F89830 /* lossless_enc_sse2.c in Sources */, A18A6CC9172DC28500419892 /* UIImage+GIF.m in Sources */, - 80377E951F2F66D000F89830 /* webp_dec.c in Sources */, - 80377CE61F2F66A100F89830 /* cpu.c in Sources */, 32D122242080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, - 80377D071F2F66A100F89830 /* lossless_neon.c in Sources */, - 80377E901F2F66D000F89830 /* vp8_dec.c in Sources */, - 80377C041F2F665300F89830 /* huffman_utils.c in Sources */, - 80377C061F2F665300F89830 /* quant_levels_dec_utils.c in Sources */, - 32FDE89B20888726008D7530 /* SDImageWebPCoder.m in Sources */, - 80377D091F2F66A100F89830 /* lossless.c in Sources */, 324DF4BA200A14DC008A84CC /* SDWebImageDefine.m in Sources */, - 80377D121F2F66A100F89830 /* rescaler_sse2.c in Sources */, - 80377CDD1F2F66A100F89830 /* alpha_processing.c in Sources */, - 80377D111F2F66A100F89830 /* rescaler_neon.c in Sources */, AB615306192DA24600A2D8E9 /* UIView+WebCacheOperation.m in Sources */, - 80377BFD1F2F665300F89830 /* color_cache_utils.c in Sources */, - 323F8BEA1F38EF770092B609 /* webp_enc.c in Sources */, - 80377CE91F2F66A100F89830 /* dec_mips32.c in Sources */, - 80377CF51F2F66A100F89830 /* enc_sse2.c in Sources */, - 323F8C141F38EF770092B609 /* muxinternal.c in Sources */, - 323F8BAE1F38EF770092B609 /* picture_rescale_enc.c in Sources */, - 80377CE31F2F66A100F89830 /* cost_mips32.c in Sources */, 32EB6D91206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, - 80377CF91F2F66A100F89830 /* filters_msa.c in Sources */, 5D5B9145188EE8DD006D06BD /* NSData+ImageContentType.m in Sources */, 53EDFB8C17623F7C00698166 /* UIImage+MultiFormat.m in Sources */, ABBE71A818C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m in Sources */, 4369C27E1D9807EC007E863A /* UIView+WebCache.m in Sources */, - 80377D011F2F66A100F89830 /* lossless_enc_neon.c in Sources */, 329A185F1FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, - 80377D131F2F66A100F89830 /* rescaler.c in Sources */, 328BB6B02081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, - 80377CDE1F2F66A100F89830 /* argb_mips_dsp_r2.c in Sources */, - 323F8BA81F38EF770092B609 /* picture_psnr_enc.c in Sources */, - 323F8BA21F38EF770092B609 /* picture_enc.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4201,10 +1894,6 @@ buildSettings = { CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - GCC_PREPROCESSOR_DEFINITIONS = ( - "WEBP_USE_INTRINSICS=1", - "$(inherited)", - ); PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = include/SDWebImage; SDKROOT = watchos; @@ -4218,10 +1907,6 @@ buildSettings = { CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - GCC_PREPROCESSOR_DEFINITIONS = ( - "WEBP_USE_INTRINSICS=1", - "$(inherited)", - ); PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = include/SDWebImage; SDKROOT = watchos; @@ -4245,10 +1930,6 @@ ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_NO_COMMON_BLOCKS = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - "WEBP_USE_INTRINSICS=1", - "$(inherited)", - ); INFOPLIST_FILE = WebImage/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; @@ -4280,10 +1961,6 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - "WEBP_USE_INTRINSICS=1", - "$(inherited)", - ); INFOPLIST_FILE = WebImage/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; @@ -4432,12 +2109,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -4460,7 +2139,6 @@ GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", - "SD_WEBP=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; @@ -4479,7 +2157,6 @@ GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_PARAMETER = NO; GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = Vendors/libwebp/src; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "-ObjC"; RUN_CLANG_STATIC_ANALYZER = YES; @@ -4500,12 +2177,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -4523,10 +2202,6 @@ ); GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - "SD_WEBP=1", - "$(inherited)", - ); GCC_TREAT_WARNINGS_AS_ERRORS = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; @@ -4542,7 +2217,6 @@ GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_PARAMETER = NO; GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = Vendors/libwebp/src; OTHER_LDFLAGS = "-ObjC"; RUN_CLANG_STATIC_ANALYZER = YES; SKIP_INSTALL = YES; diff --git a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX.xcscheme b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX.xcscheme index 703894ed..88623ffd 100644 --- a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX.xcscheme +++ b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX.xcscheme @@ -1,6 +1,6 @@ @@ -37,7 +36,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS static.xcscheme b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS static.xcscheme index 6acfdae8..4f7b486b 100644 --- a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS static.xcscheme +++ b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS static.xcscheme @@ -1,6 +1,6 @@ @@ -37,7 +36,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS.xcscheme b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS.xcscheme index 042f8b28..6ce59516 100644 --- a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS.xcscheme +++ b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS.xcscheme @@ -1,6 +1,6 @@ @@ -37,7 +36,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage tvOS.xcscheme b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage tvOS.xcscheme index 9531bb10..051eaaec 100644 --- a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage tvOS.xcscheme +++ b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage tvOS.xcscheme @@ -1,6 +1,6 @@ @@ -37,7 +36,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS static.xcscheme b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS static.xcscheme index 3b5a1a6d..4f74b360 100644 --- a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS static.xcscheme +++ b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS static.xcscheme @@ -1,6 +1,6 @@ @@ -37,7 +36,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS.xcscheme b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS.xcscheme index 3ee46b83..3759187f 100644 --- a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS.xcscheme +++ b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS.xcscheme @@ -1,6 +1,6 @@ @@ -37,7 +36,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/SDWebImage.xcworkspace/contents.xcworkspacedata b/SDWebImage.xcworkspace/contents.xcworkspacedata index b2e04319..3d719145 100644 --- a/SDWebImage.xcworkspace/contents.xcworkspacedata +++ b/SDWebImage.xcworkspace/contents.xcworkspacedata @@ -1,6 +1,9 @@ + + @@ -25,4 +28,7 @@ + + diff --git a/SDWebImage.xcworkspace/xcshareddata/xcschemes/SDWebImage iOS Demo.xcscheme b/SDWebImage.xcworkspace/xcshareddata/xcschemes/SDWebImage iOS Demo.xcscheme index b7da4063..e4a3bb64 100644 --- a/SDWebImage.xcworkspace/xcshareddata/xcschemes/SDWebImage iOS Demo.xcscheme +++ b/SDWebImage.xcworkspace/xcshareddata/xcschemes/SDWebImage iOS Demo.xcscheme @@ -1,6 +1,6 @@ @@ -46,7 +45,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/SDWebImage/SDImageCodersManager.h b/SDWebImage/SDImageCodersManager.h index e64c4c20..0d300786 100644 --- a/SDWebImage/SDImageCodersManager.h +++ b/SDWebImage/SDImageCodersManager.h @@ -17,10 +17,10 @@ Note: the `coders` getter will return the coders in their reversed order Example: - - by default we internally set coders = `IOCoder`, `GIFCoder`, `APNGCoder` and `WebPCoder` (When WebP subspec is available). - - calling `coders` will return `@[WebPCoder, IOCoder]` + - by default we internally set coders = `IOCoder`, `GIFCoder` + - calling `coders` will return `@[IOCoder, GIFCoder]` - call `[addCoder:[MyCrazyCoder new]]` - - calling `coders` now returns `@[MyCrazyCoder, WebPCoder, IOCoder]` + - calling `coders` now returns `@[MyCrazyCoder, IOCoder, GIFCoder]` Coders ------ diff --git a/SDWebImage/SDImageCodersManager.m b/SDWebImage/SDImageCodersManager.m index 131925d1..b15ae921 100644 --- a/SDWebImage/SDImageCodersManager.m +++ b/SDWebImage/SDImageCodersManager.m @@ -10,9 +10,6 @@ #import "SDImageIOCoder.h" #import "SDImageGIFCoder.h" #import "SDImageAPNGCoder.h" -#ifdef SD_WEBP -#import "SDImageWebPCoder.h" -#endif @interface SDImageCodersManager () @@ -35,9 +32,6 @@ if (self = [super init]) { // initialize with default coders NSMutableArray> *mutableCoders = [@[[SDImageIOCoder sharedCoder], [SDImageGIFCoder sharedCoder], [SDImageAPNGCoder sharedCoder]] mutableCopy]; -#ifdef SD_WEBP - [mutableCoders addObject:[SDImageWebPCoder sharedCoder]]; -#endif _coders = [mutableCoders copy]; _codersLock = dispatch_semaphore_create(1); } diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index bd7a836a..55323361 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -112,11 +112,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; } headerDictionary[@"User-Agent"] = userAgent; } -#ifdef SD_WEBP - headerDictionary[@"Accept"] = @"image/webp,image/*;q=0.8"; -#else headerDictionary[@"Accept"] = @"image/*;q=0.8"; -#endif _HTTPHeaders = [headerDictionary copy]; _operationsLock = dispatch_semaphore_create(1); NSURLSessionConfiguration *sessionConfiguration = _config.sessionConfiguration; diff --git a/SDWebImage/WebP/SDImageWebPCoder.h b/SDWebImage/WebP/SDImageWebPCoder.h deleted file mode 100644 index ae62a6b8..00000000 --- a/SDWebImage/WebP/SDImageWebPCoder.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * This file is part of the SDWebImage package. - * (c) Olivier Poitrey - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#ifdef SD_WEBP - -#import -#import "SDImageCoder.h" - -/** - Built in coder that supports WebP and animated WebP - */ -@interface SDImageWebPCoder : NSObject - -@property (nonatomic, class, readonly, nonnull) SDImageWebPCoder *sharedCoder; - -@end - -#endif diff --git a/SDWebImage/WebP/SDImageWebPCoder.m b/SDWebImage/WebP/SDImageWebPCoder.m deleted file mode 100644 index 56f6e6b4..00000000 --- a/SDWebImage/WebP/SDImageWebPCoder.m +++ /dev/null @@ -1,827 +0,0 @@ -/* - * This file is part of the SDWebImage package. - * (c) Olivier Poitrey - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#ifdef SD_WEBP - -#import "SDImageWebPCoder.h" -#import "SDImageCoderHelper.h" -#import "NSImage+Compatibility.h" -#import "UIImage+Metadata.h" -#import "UIImage+ForceDecode.h" -#if __has_include() && __has_include() && __has_include() && __has_include() -#import -#import -#import -#import -#else -#import "webp/decode.h" -#import "webp/encode.h" -#import "webp/demux.h" -#import "webp/mux.h" -#endif -#import - -@interface SDWebPCoderFrame : NSObject - -@property (nonatomic, assign) NSUInteger index; // Frame index (zero based) -@property (nonatomic, assign) NSTimeInterval duration; // Frame duration in seconds -@property (nonatomic, assign) NSUInteger width; // Frame width -@property (nonatomic, assign) NSUInteger height; // Frame height -@property (nonatomic, assign) NSUInteger offsetX; // Frame origin.x in canvas (left-bottom based) -@property (nonatomic, assign) NSUInteger offsetY; // Frame origin.y in canvas (left-bottom based) -@property (nonatomic, assign) BOOL hasAlpha; // Whether frame contains alpha -@property (nonatomic, assign) BOOL isFullSize; // Whether frame size is equal to canvas size -@property (nonatomic, assign) WebPMuxAnimBlend blend; // Frame dispose method -@property (nonatomic, assign) WebPMuxAnimDispose dispose; // Frame blend operation -@property (nonatomic, assign) NSUInteger blendFromIndex; // The nearest previous frame index which blend mode is WEBP_MUX_BLEND - -@end - -@implementation SDWebPCoderFrame -@end - -@implementation SDImageWebPCoder { - WebPIDecoder *_idec; - WebPDemuxer *_demux; - NSData *_imageData; - CGFloat _scale; - NSUInteger _loopCount; - NSUInteger _frameCount; - NSArray *_frames; - CGContextRef _canvas; - BOOL _hasAnimation; - BOOL _hasAlpha; - BOOL _finished; - CGFloat _canvasWidth; - CGFloat _canvasHeight; - dispatch_semaphore_t _lock; - NSUInteger _currentBlendIndex; -} - -- (void)dealloc { - if (_idec) { - WebPIDelete(_idec); - _idec = NULL; - } - if (_demux) { - WebPDemuxDelete(_demux); - _demux = NULL; - } - if (_canvas) { - CGContextRelease(_canvas); - _canvas = NULL; - } -} - -+ (instancetype)sharedCoder { - static SDImageWebPCoder *coder; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - coder = [[SDImageWebPCoder alloc] init]; - }); - return coder; -} - -#pragma mark - Decode -- (BOOL)canDecodeFromData:(nullable NSData *)data { - return ([NSData sd_imageFormatForImageData:data] == SDImageFormatWebP); -} - -- (BOOL)canIncrementalDecodeFromData:(NSData *)data { - return ([NSData sd_imageFormatForImageData:data] == SDImageFormatWebP); -} - -- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderOptions *)options { - if (!data) { - return nil; - } - - WebPData webpData; - WebPDataInit(&webpData); - webpData.bytes = data.bytes; - webpData.size = data.length; - WebPDemuxer *demuxer = WebPDemux(&webpData); - if (!demuxer) { - return nil; - } - - uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS); - BOOL hasAnimation = flags & ANIMATION_FLAG; - BOOL decodeFirstFrame = [options[SDImageCoderDecodeFirstFrameOnly] boolValue]; - CGFloat scale = 1; - NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; - if (scaleFactor != nil) { - scale = [scaleFactor doubleValue]; - if (scale < 1) { - scale = 1; - } - } - if (!hasAnimation) { - // for static single webp image - CGImageRef imageRef = [self sd_createWebpImageWithData:webpData]; - if (!imageRef) { - return nil; - } -#if SD_UIKIT || SD_WATCH - UIImage *staticImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; -#else - UIImage *staticImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp]; -#endif - CGImageRelease(imageRef); - WebPDemuxDelete(demuxer); - return staticImage; - } - - // for animated webp image - WebPIterator iter; - // libwebp's index start with 1 - if (!WebPDemuxGetFrame(demuxer, 1, &iter)) { - WebPDemuxReleaseIterator(&iter); - WebPDemuxDelete(demuxer); - return nil; - } - - if (decodeFirstFrame) { - // first frame for animated webp image - CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment]; -#if SD_UIKIT || SD_WATCH - UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; -#else - UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp]; -#endif - firstFrameImage.sd_imageFormat = SDImageFormatWebP; - CGImageRelease(imageRef); - WebPDemuxReleaseIterator(&iter); - WebPDemuxDelete(demuxer); - return firstFrameImage; - } - - int loopCount = WebPDemuxGetI(demuxer, WEBP_FF_LOOP_COUNT); - int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH); - int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT); - BOOL hasAlpha = flags & ALPHA_FLAG; - CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; - bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; - CGContextRef canvas = CGBitmapContextCreate(NULL, canvasWidth, canvasHeight, 8, 0, [SDImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo); - if (!canvas) { - WebPDemuxDelete(demuxer); - return nil; - } - - NSMutableArray *frames = [NSMutableArray array]; - - do { - @autoreleasepool { - CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:canvas iterator:iter]; - if (!imageRef) { - continue; - } -#if SD_UIKIT || SD_WATCH - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; -#else - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp]; -#endif - CGImageRelease(imageRef); - - NSTimeInterval duration = [self sd_frameDurationWithIterator:iter]; - SDImageFrame *frame = [SDImageFrame frameWithImage:image duration:duration]; - [frames addObject:frame]; - } - - } while (WebPDemuxNextFrame(&iter)); - - WebPDemuxReleaseIterator(&iter); - WebPDemuxDelete(demuxer); - CGContextRelease(canvas); - - UIImage *animatedImage = [SDImageCoderHelper animatedImageWithFrames:frames]; - animatedImage.sd_imageLoopCount = loopCount; - animatedImage.sd_imageFormat = SDImageFormatWebP; - - return animatedImage; -} - -#pragma mark - Progressive Decode -- (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)options { - self = [super init]; - if (self) { - // Progressive images need transparent, so always use premultiplied BGRA - _idec = WebPINewRGB(MODE_bgrA, NULL, 0, 0); - CGFloat scale = 1; - NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; - if (scaleFactor != nil) { - scale = [scaleFactor doubleValue]; - if (scale < 1) { - scale = 1; - } - } - _scale = scale; - } - return self; -} - -- (void)updateIncrementalData:(NSData *)data finished:(BOOL)finished { - if (_finished) { - return; - } - _imageData = data; - _finished = finished; - VP8StatusCode status = WebPIUpdate(_idec, data.bytes, data.length); - if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) { - return; - } - // libwebp current does not support progressive decoding for animated image, so no need to scan and update the frame information -} - -- (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options { - UIImage *image; - - int width = 0; - int height = 0; - int last_y = 0; - int stride = 0; - uint8_t *rgba = WebPIDecGetRGB(_idec, &last_y, &width, &height, &stride); - // last_y may be 0, means no enough bitmap data to decode, ignore this - if (width + height > 0 && last_y > 0 && height >= last_y) { - // Construct a UIImage from the decoded RGBA value array - size_t rgbaSize = last_y * stride; - CGDataProviderRef provider = - CGDataProviderCreateWithData(NULL, rgba, rgbaSize, NULL); - CGColorSpaceRef colorSpaceRef = [SDImageCoderHelper colorSpaceGetDeviceRGB]; - - CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst; - size_t components = 4; - CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; - // Why to use last_y for image height is because of libwebp's bug (https://bugs.chromium.org/p/webp/issues/detail?id=362) - // It will not keep memory barrier safe on x86 architechure (macOS & iPhone simulator) but on ARM architecture (iPhone & iPad & tv & watch) it works great - // If different threads use WebPIDecGetRGB to grab rgba bitmap, it will contain the previous decoded bitmap data - // So this will cause our drawed image looks strange(above is the current part but below is the previous part) - // We only grab the last_y height and draw the last_y height instead of total height image - // Besides fix, this can enhance performance since we do not need to create extra bitmap - CGImageRef imageRef = CGImageCreate(width, last_y, 8, components * 8, components * width, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); - - CGDataProviderRelease(provider); - - if (!imageRef) { - return nil; - } - - CGContextRef canvas = CGBitmapContextCreate(NULL, width, height, 8, 0, [SDImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo); - if (!canvas) { - CGImageRelease(imageRef); - return nil; - } - - // Only draw the last_y image height, keep remains transparent, in Core Graphics coordinate system - CGContextDrawImage(canvas, CGRectMake(0, height - last_y, width, last_y), imageRef); - CGImageRef newImageRef = CGBitmapContextCreateImage(canvas); - CGImageRelease(imageRef); - if (!newImageRef) { - CGContextRelease(canvas); - return nil; - } - CGFloat scale = _scale; - NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; - if (scaleFactor != nil) { - scale = [scaleFactor doubleValue]; - if (scale < 1) { - scale = 1; - } - } - -#if SD_UIKIT || SD_WATCH - image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale orientation:UIImageOrientationUp]; -#else - image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale orientation:kCGImagePropertyOrientationUp]; -#endif - image.sd_isDecoded = YES; // Already drawn on bitmap context above - image.sd_imageFormat = SDImageFormatWebP; - CGImageRelease(newImageRef); - CGContextRelease(canvas); - } - - return image; -} - -- (void)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter { - size_t canvasHeight = CGBitmapContextGetHeight(canvas); - CGFloat tmpX = iter.x_offset; - CGFloat tmpY = canvasHeight - iter.height - iter.y_offset; - CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height); - - if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { - CGContextClearRect(canvas, imageRect); - } else { - CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment]; - if (!imageRef) { - return; - } - BOOL shouldBlend = iter.blend_method == WEBP_MUX_BLEND; - // If not blend, cover the target image rect. (firstly clear then draw) - if (!shouldBlend) { - CGContextClearRect(canvas, imageRect); - } - CGContextDrawImage(canvas, imageRect, imageRef); - CGImageRelease(imageRef); - } -} - -- (nullable CGImageRef)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter CF_RETURNS_RETAINED { - CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment]; - if (!imageRef) { - return nil; - } - - size_t canvasHeight = CGBitmapContextGetHeight(canvas); - CGFloat tmpX = iter.x_offset; - CGFloat tmpY = canvasHeight - iter.height - iter.y_offset; - CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height); - BOOL shouldBlend = iter.blend_method == WEBP_MUX_BLEND; - - // If not blend, cover the target image rect. (firstly clear then draw) - if (!shouldBlend) { - CGContextClearRect(canvas, imageRect); - } - CGContextDrawImage(canvas, imageRect, imageRef); - CGImageRef newImageRef = CGBitmapContextCreateImage(canvas); - - CGImageRelease(imageRef); - - if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { - CGContextClearRect(canvas, imageRect); - } - - return newImageRef; -} - -- (nullable CGImageRef)sd_createWebpImageWithData:(WebPData)webpData CF_RETURNS_RETAINED { - WebPDecoderConfig config; - if (!WebPInitDecoderConfig(&config)) { - return nil; - } - - if (WebPGetFeatures(webpData.bytes, webpData.size, &config.input) != VP8_STATUS_OK) { - return nil; - } - - BOOL hasAlpha = config.input.has_alpha; - // iOS prefer BGRA8888 (premultiplied) or BGRX8888 bitmapInfo for screen rendering, which is same as `UIGraphicsBeginImageContext()` or `- [CALayer drawInContext:]` - // use this bitmapInfo, combined with right colorspace, even without decode, can still avoid extra CA::Render::copy_image(which marked `Color Copied Images` from Instruments) - WEBP_CSP_MODE colorspace = MODE_bgrA; - CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; - bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; - config.options.use_threads = 1; - config.output.colorspace = colorspace; - - // Decode the WebP image data into a RGBA value array - if (WebPDecode(webpData.bytes, webpData.size, &config) != VP8_STATUS_OK) { - return nil; - } - - int width = config.input.width; - int height = config.input.height; - if (config.options.use_scaling) { - width = config.options.scaled_width; - height = config.options.scaled_height; - } - - // Construct a UIImage from the decoded RGBA value array - CGDataProviderRef provider = - CGDataProviderCreateWithData(NULL, config.output.u.RGBA.rgba, config.output.u.RGBA.size, FreeImageData); - size_t bitsPerComponent = 8; - size_t bitsPerPixel = 32; - size_t bytesPerRow = config.output.u.RGBA.stride; - CGColorSpaceRef colorSpaceRef = [SDImageCoderHelper colorSpaceGetDeviceRGB]; - CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; - CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); - - CGDataProviderRelease(provider); - - return imageRef; -} - -- (NSTimeInterval)sd_frameDurationWithIterator:(WebPIterator)iter { - int duration = iter.duration; - if (duration <= 10) { - // WebP standard says 0 duration is used for canvas updating but not showing image, but actually Chrome and other implementations set it to 100ms if duration is lower or equal than 10ms - // Some animated WebP images also created without duration, we should keep compatibility - duration = 100; - } - return duration / 1000.0; -} - -#pragma mark - Encode -- (BOOL)canEncodeToFormat:(SDImageFormat)format { - return (format == SDImageFormatWebP); -} - -- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDImageCoderOptions *)options { - if (!image) { - return nil; - } - - NSData *data; - - double compressionQuality = 1; - if (options[SDImageCoderEncodeCompressionQuality]) { - compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue]; - } - NSArray *frames = [SDImageCoderHelper framesFromAnimatedImage:image]; - - BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; - if (encodeFirstFrame || frames.count == 0) { - // for static single webp image - data = [self sd_encodedWebpDataWithImage:image quality:compressionQuality]; - } else { - // for animated webp image - WebPMux *mux = WebPMuxNew(); - if (!mux) { - return nil; - } - for (size_t i = 0; i < frames.count; i++) { - SDImageFrame *currentFrame = frames[i]; - NSData *webpData = [self sd_encodedWebpDataWithImage:currentFrame.image quality:compressionQuality]; - int duration = currentFrame.duration * 1000; - WebPMuxFrameInfo frame = { .bitstream.bytes = webpData.bytes, - .bitstream.size = webpData.length, - .duration = duration, - .id = WEBP_CHUNK_ANMF, - .dispose_method = WEBP_MUX_DISPOSE_BACKGROUND, // each frame will clear canvas - .blend_method = WEBP_MUX_NO_BLEND - }; - if (WebPMuxPushFrame(mux, &frame, 0) != WEBP_MUX_OK) { - WebPMuxDelete(mux); - return nil; - } - } - - int loopCount = (int)image.sd_imageLoopCount; - WebPMuxAnimParams params = { .bgcolor = 0, - .loop_count = loopCount - }; - if (WebPMuxSetAnimationParams(mux, ¶ms) != WEBP_MUX_OK) { - WebPMuxDelete(mux); - return nil; - } - - WebPData outputData; - WebPMuxError error = WebPMuxAssemble(mux, &outputData); - WebPMuxDelete(mux); - if (error != WEBP_MUX_OK) { - return nil; - } - data = [NSData dataWithBytes:outputData.bytes length:outputData.size]; - WebPDataClear(&outputData); - } - - return data; -} - -- (nullable NSData *)sd_encodedWebpDataWithImage:(nullable UIImage *)image quality:(double)quality { - if (!image) { - return nil; - } - - NSData *webpData; - CGImageRef imageRef = image.CGImage; - - size_t width = CGImageGetWidth(imageRef); - size_t height = CGImageGetHeight(imageRef); - if (width == 0 || width > WEBP_MAX_DIMENSION) { - return nil; - } - if (height == 0 || height > WEBP_MAX_DIMENSION) { - return nil; - } - - size_t bytesPerRow = CGImageGetBytesPerRow(imageRef); - CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); - CGImageAlphaInfo alphaInfo = bitmapInfo & kCGBitmapAlphaInfoMask; - CGBitmapInfo byteOrderInfo = bitmapInfo & kCGBitmapByteOrderMask; - BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone || - alphaInfo == kCGImageAlphaNoneSkipFirst || - alphaInfo == kCGImageAlphaNoneSkipLast); - BOOL byteOrderNormal = NO; - switch (byteOrderInfo) { - case kCGBitmapByteOrderDefault: { - byteOrderNormal = YES; - } break; - case kCGBitmapByteOrder32Little: { - } break; - case kCGBitmapByteOrder32Big: { - byteOrderNormal = YES; - } break; - default: break; - } - // If we can not get bitmap buffer, early return - CGDataProviderRef dataProvider = CGImageGetDataProvider(imageRef); - if (!dataProvider) { - return nil; - } - CFDataRef dataRef = CGDataProviderCopyData(dataProvider); - if (!dataRef) { - return nil; - } - - uint8_t *rgba = NULL; - // We could not assume that input CGImage's color mode is always RGB888/RGBA8888. Convert all other cases to target color mode using vImage - if (byteOrderNormal && ((alphaInfo == kCGImageAlphaNone) || (alphaInfo == kCGImageAlphaLast))) { - // If the input CGImage is already RGB888/RGBA8888 - rgba = (uint8_t *)CFDataGetBytePtr(dataRef); - } else { - // Convert all other cases to target color mode using vImage - vImageConverterRef convertor = NULL; - vImage_Error error = kvImageNoError; - - vImage_CGImageFormat srcFormat = { - .bitsPerComponent = (uint32_t)CGImageGetBitsPerComponent(imageRef), - .bitsPerPixel = (uint32_t)CGImageGetBitsPerPixel(imageRef), - .colorSpace = CGImageGetColorSpace(imageRef), - .bitmapInfo = bitmapInfo - }; - vImage_CGImageFormat destFormat = { - .bitsPerComponent = 8, - .bitsPerPixel = hasAlpha ? 32 : 24, - .colorSpace = [SDImageCoderHelper colorSpaceGetDeviceRGB], - .bitmapInfo = hasAlpha ? kCGImageAlphaLast | kCGBitmapByteOrderDefault : kCGImageAlphaNone | kCGBitmapByteOrderDefault // RGB888/RGBA8888 (Non-premultiplied to works for libwebp) - }; - - convertor = vImageConverter_CreateWithCGImageFormat(&srcFormat, &destFormat, NULL, kvImageNoFlags, &error); - if (error != kvImageNoError) { - CFRelease(dataRef); - return nil; - } - - vImage_Buffer src = { - .data = (uint8_t *)CFDataGetBytePtr(dataRef), - .width = width, - .height = height, - .rowBytes = bytesPerRow - }; - vImage_Buffer dest; - - error = vImageBuffer_Init(&dest, height, width, destFormat.bitsPerPixel, kvImageNoFlags); - if (error != kvImageNoError) { - CFRelease(dataRef); - return nil; - } - - // Convert input color mode to RGB888/RGBA8888 - error = vImageConvert_AnyToAny(convertor, &src, &dest, NULL, kvImageNoFlags); - if (error != kvImageNoError) { - CFRelease(dataRef); - return nil; - } - - rgba = dest.data; // Converted buffer - bytesPerRow = dest.rowBytes; // Converted bytePerRow - CFRelease(dataRef); - dataRef = NULL; - } - - uint8_t *data = NULL; // Output WebP data - float qualityFactor = quality * 100; // WebP quality is 0-100 - // Encode RGB888/RGBA8888 buffer to WebP data - size_t size; - if (hasAlpha) { - size = WebPEncodeRGBA(rgba, (int)width, (int)height, (int)bytesPerRow, qualityFactor, &data); - } else { - size = WebPEncodeRGB(rgba, (int)width, (int)height, (int)bytesPerRow, qualityFactor, &data); - } - if (dataRef) { - CFRelease(dataRef); // free non-converted rgba buffer - dataRef = NULL; - } else { - free(rgba); // free converted rgba buffer - rgba = NULL; - } - - if (size) { - // success - webpData = [NSData dataWithBytes:data length:size]; - } - if (data) { - WebPFree(data); - } - - return webpData; -} - -static void FreeImageData(void *info, const void *data, size_t size) { - free((void *)data); -} - -#pragma mark - SDAnimatedImageCoder -- (instancetype)initWithAnimatedImageData:(NSData *)data options:(nullable SDImageCoderOptions *)options { - if (!data) { - return nil; - } - if (self) { - WebPData webpData; - WebPDataInit(&webpData); - webpData.bytes = data.bytes; - webpData.size = data.length; - WebPDemuxer *demuxer = WebPDemux(&webpData); - if (!demuxer) { - return nil; - } - BOOL framesValid = [self scanAndCheckFramesValidWithDemuxer:demuxer]; - if (!framesValid) { - WebPDemuxDelete(demuxer); - return nil; - } - CGFloat scale = 1; - NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor]; - if (scaleFactor != nil) { - scale = [scaleFactor doubleValue]; - if (scale < 1) { - scale = 1; - } - } - _scale = scale; - _demux = demuxer; - _imageData = data; - _currentBlendIndex = NSNotFound; - _lock = dispatch_semaphore_create(1); - } - return self; -} - -- (BOOL)scanAndCheckFramesValidWithDemuxer:(WebPDemuxer *)demuxer { - if (!demuxer) { - return NO; - } - WebPIterator iter; - if (!WebPDemuxGetFrame(demuxer, 1, &iter)) { - WebPDemuxReleaseIterator(&iter); - return NO; - } - - uint32_t iterIndex = 0; - uint32_t lastBlendIndex = 0; - uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS); - BOOL hasAnimation = flags & ANIMATION_FLAG; - BOOL hasAlpha = flags & ALPHA_FLAG; - int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH); - int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT); - uint32_t frameCount = WebPDemuxGetI(demuxer, WEBP_FF_FRAME_COUNT); - uint32_t loopCount = WebPDemuxGetI(demuxer, WEBP_FF_LOOP_COUNT); - NSMutableArray *frames = [NSMutableArray array]; - - // We should loop all the frames and scan each frames' blendFromIndex for later decoding, this can also ensure all frames is valid - do { - SDWebPCoderFrame *frame = [[SDWebPCoderFrame alloc] init]; - frame.index = iterIndex; - frame.duration = [self sd_frameDurationWithIterator:iter]; - frame.width = iter.width; - frame.height = iter.height; - frame.hasAlpha = iter.has_alpha; - frame.dispose = iter.dispose_method; - frame.blend = iter.blend_method; - frame.offsetX = iter.x_offset; - frame.offsetY = canvasHeight - iter.y_offset - iter.height; - - BOOL sizeEqualsToCanvas = (iter.width == canvasWidth && iter.height == canvasHeight); - BOOL offsetIsZero = (iter.x_offset == 0 && iter.y_offset == 0); - frame.isFullSize = (sizeEqualsToCanvas && offsetIsZero); - - if ((!frame.blend || !frame.hasAlpha) && frame.isFullSize) { - lastBlendIndex = iterIndex; - frame.blendFromIndex = iterIndex; - } else { - if (frame.dispose && frame.isFullSize) { - frame.blendFromIndex = lastBlendIndex; - lastBlendIndex = iterIndex + 1; - } else { - frame.blendFromIndex = lastBlendIndex; - } - } - iterIndex++; - [frames addObject:frame]; - } while (WebPDemuxNextFrame(&iter)); - WebPDemuxReleaseIterator(&iter); - - if (frames.count != frameCount) { - return NO; - } - _frames = [frames copy]; - _hasAnimation = hasAnimation; - _hasAlpha = hasAlpha; - _canvasWidth = canvasWidth; - _canvasHeight = canvasHeight; - _frameCount = frameCount; - _loopCount = loopCount; - - return YES; -} - -- (NSData *)animatedImageData { - return _imageData; -} - -- (NSUInteger)animatedImageLoopCount { - return _loopCount; -} - -- (NSUInteger)animatedImageFrameCount { - return _frameCount; -} - -- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { - if (index >= _frameCount) { - return 0; - } - return _frames[index].duration; -} - -- (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { - UIImage *image; - if (index >= _frameCount) { - return nil; - } - LOCKBLOCK({ - image = [self safeAnimatedImageFrameAtIndex:index]; - }); - return image; -} - -- (UIImage *)safeAnimatedImageFrameAtIndex:(NSUInteger)index { - if (!_canvas) { - CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; - bitmapInfo |= _hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; - CGContextRef canvas = CGBitmapContextCreate(NULL, _canvasWidth, _canvasHeight, 8, 0, [SDImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo); - if (!canvas) { - return nil; - } - _canvas = canvas; - } - - SDWebPCoderFrame *frame = _frames[index]; - UIImage *image; - WebPIterator iter; - if (_currentBlendIndex + 1 == index) { - // If current blend index is equal to request index, normal serial process - _currentBlendIndex = index; - // libwebp's index start with 1 - if (!WebPDemuxGetFrame(_demux, (int)(index + 1), &iter)) { - WebPDemuxReleaseIterator(&iter); - return nil; - } - CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter]; - if (!imageRef) { - return nil; - } -#if SD_UIKIT || SD_WATCH - image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:UIImageOrientationUp]; -#else - image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:kCGImagePropertyOrientationUp]; -#endif - CGImageRelease(imageRef); - } else { - // Else, this can happen when one image set to different imageViews or one loop end. So we should clear the shared cavans. - if (_currentBlendIndex != NSNotFound) { - CGContextClearRect(_canvas, CGRectMake(0, 0, _canvasWidth, _canvasHeight)); - } - _currentBlendIndex = index; - - // Then, loop from the blend from index, draw each of previous frames on the canvas. - // We use do while loop to call `WebPDemuxNextFrame`(fast), only (startIndex == endIndex) need to create image instance - size_t startIndex = frame.blendFromIndex; - size_t endIndex = frame.index; - if (!WebPDemuxGetFrame(_demux, (int)(startIndex + 1), &iter)) { - WebPDemuxReleaseIterator(&iter); - return nil; - } - do { - @autoreleasepool { - if ((size_t)iter.frame_num == endIndex) { - [self sd_blendWebpImageWithCanvas:_canvas iterator:iter]; - } else { - CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter]; - if (!imageRef) { - return nil; - } -#if SD_UIKIT || SD_WATCH - image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:UIImageOrientationUp]; -#else - image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:kCGImagePropertyOrientationUp]; -#endif - CGImageRelease(imageRef); - } - } - } while ((size_t)iter.frame_num < (endIndex + 1) && WebPDemuxNextFrame(&iter)); - } - - WebPDemuxReleaseIterator(&iter); - return image; -} - -@end - -#endif - diff --git a/SDWebImage/WebP/UIImage+WebP.h b/SDWebImage/WebP/UIImage+WebP.h deleted file mode 100644 index b799b53c..00000000 --- a/SDWebImage/WebP/UIImage+WebP.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This file is part of the SDWebImage package. - * (c) Olivier Poitrey - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#ifdef SD_WEBP - -#import "SDWebImageCompat.h" - -// This category is just use as a convenience method. For more detail control, use methods in `UIImage+MultiFormat.h` or directlly use `SDImageCoder` -@interface UIImage (WebP) - -/** - Create a image from the WebP data. - This will create animated image if the data is Animated WebP. And will create a static image is the data is Static WebP. - - @param data The WebP data - @return The created image - */ -+ (nullable UIImage *)sd_imageWithWebPData:(nullable NSData *)data; - -@end - -#endif diff --git a/SDWebImage/WebP/UIImage+WebP.m b/SDWebImage/WebP/UIImage+WebP.m deleted file mode 100644 index 011b8ad2..00000000 --- a/SDWebImage/WebP/UIImage+WebP.m +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This file is part of the SDWebImage package. - * (c) Olivier Poitrey - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#ifdef SD_WEBP - -#import "UIImage+WebP.h" -#import "SDImageWebPCoder.h" - -@implementation UIImage (WebP) - -+ (nullable UIImage *)sd_imageWithWebPData:(nullable NSData *)data { - if (!data) { - return nil; - } - return [[SDImageWebPCoder sharedCoder] decodedImageWithData:data options:0]; -} - -@end - -#endif diff --git a/Tests/Podfile b/Tests/Podfile index ac090843..4c40e711 100644 --- a/Tests/Podfile +++ b/Tests/Podfile @@ -9,7 +9,6 @@ target 'Tests' do platform :ios, '8.0' pod 'Expecta' pod 'KVOController' - pod 'SDWebImage/WebP', :path => '../' pod 'SDWebImage/MapKit', :path => '../' end @@ -18,7 +17,6 @@ target 'Tests Mac' do platform :osx, '10.10' pod 'Expecta' pod 'KVOController' - pod 'SDWebImage/WebP', :path => '../' pod 'SDWebImage/MapKit', :path => '../' end diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 46b738cd..de3eddfb 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -11,8 +11,6 @@ 1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */; }; 2D7AF0601F329763000083C2 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; }; 320630412085A37C006E0FA4 /* SDAnimatedImageTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */; }; - 321259EC1F39E3240096FE0E /* TestImageStatic.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259EB1F39E3240096FE0E /* TestImageStatic.webp */; }; - 321259EE1F39E4110096FE0E /* TestImageAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */; }; 3226ECBB20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */; }; 3226ECBC20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */; }; 323B8E1F20862322008952BE /* SDWebImageTestLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 323B8E1E20862322008952BE /* SDWebImageTestLoader.m */; }; @@ -40,8 +38,6 @@ 32B99EA4203B31360017FD66 /* TestImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */; }; 32B99EA5203B31360017FD66 /* TestImageLarge.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 43828A441DA67F9900000E62 /* TestImageLarge.jpg */; }; 32B99EA6203B31360017FD66 /* TestImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB81D7EF8260086B6E9 /* TestImage.png */; }; - 32B99EA7203B31360017FD66 /* TestImageAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */; }; - 32B99EA8203B31360017FD66 /* TestImageStatic.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259EB1F39E3240096FE0E /* TestImageStatic.webp */; }; 32B99EA9203B34B60017FD66 /* SDImageCoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDImageCoderTests.m */; }; 32B99EAA203B365F0017FD66 /* SDImageCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA248D68195475D800390AB0 /* SDImageCacheTests.m */; }; 32B99EAB203B36620017FD66 /* SDWebImageManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA248D6A195476AC00390AB0 /* SDWebImageManagerTests.m */; }; @@ -72,8 +68,6 @@ 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderTests.m; sourceTree = ""; }; 2D7AF05E1F329763000083C2 /* SDTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDTestCase.h; sourceTree = ""; }; 2D7AF05F1F329763000083C2 /* SDTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDTestCase.m; sourceTree = ""; }; - 321259EB1F39E3240096FE0E /* TestImageStatic.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageStatic.webp; sourceTree = ""; }; - 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageAnimated.webp; sourceTree = ""; }; 3226ECB920754F7700FAFACF /* SDWebImageTestDownloadOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestDownloadOperation.h; sourceTree = ""; }; 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestDownloadOperation.m; sourceTree = ""; }; 323B8E1D20862322008952BE /* SDWebImageTestLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestLoader.h; sourceTree = ""; }; @@ -159,8 +153,6 @@ 433BBBB81D7EF8260086B6E9 /* TestImage.png */, 327A418B211D660600495442 /* TestImage.heic */, 32905E63211D786E00460FCF /* TestImage.heif */, - 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */, - 321259EB1F39E3240096FE0E /* TestImageStatic.webp */, 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */, ); path = Images; @@ -298,7 +290,7 @@ DA248D461954721A00390AB0 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0900; + LastUpgradeCheck = 0940; TargetAttributes = { 32B99E91203B2DF90017FD66 = { CreatedOnToolsVersion = 9.2; @@ -336,8 +328,6 @@ 32B99EA2203B31360017FD66 /* MonochromeTestImage.jpg in Resources */, 32905E65211D786E00460FCF /* TestImage.heif in Resources */, 327A418D211D660600495442 /* TestImage.heic in Resources */, - 32B99EA8203B31360017FD66 /* TestImageStatic.webp in Resources */, - 32B99EA7203B31360017FD66 /* TestImageAnimated.webp in Resources */, 32B99EA5203B31360017FD66 /* TestImageLarge.jpg in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -347,12 +337,10 @@ buildActionMask = 2147483647; files = ( 327A418C211D660600495442 /* TestImage.heic in Resources */, - 321259EE1F39E4110096FE0E /* TestImageAnimated.webp in Resources */, 5F7F38AD1AE2A77A00B0E330 /* TestImage.jpg in Resources */, 32905E64211D786E00460FCF /* TestImage.heif in Resources */, 43828A451DA67F9900000E62 /* TestImageLarge.jpg in Resources */, 433BBBB71D7EF8200086B6E9 /* TestImage.gif in Resources */, - 321259EC1F39E3240096FE0E /* TestImageStatic.webp in Resources */, DA248D61195472AA00390AB0 /* InfoPlist.strings in Resources */, 433BBBB91D7EF8260086B6E9 /* TestImage.png in Resources */, 327054E2206CEFF3006EA328 /* TestImageAnimated.apng in Resources */, @@ -373,14 +361,12 @@ "${BUILT_PRODUCTS_DIR}/Expecta-macOS/Expecta.framework", "${BUILT_PRODUCTS_DIR}/KVOController-macOS/KVOController.framework", "${BUILT_PRODUCTS_DIR}/SDWebImage-macOS/SDWebImage.framework", - "${BUILT_PRODUCTS_DIR}/libwebp-macOS/libwebp.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Expecta.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KVOController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -433,14 +419,12 @@ "${BUILT_PRODUCTS_DIR}/Expecta-iOS/Expecta.framework", "${BUILT_PRODUCTS_DIR}/KVOController-iOS/KVOController.framework", "${BUILT_PRODUCTS_DIR}/SDWebImage-iOS/SDWebImage.framework", - "${BUILT_PRODUCTS_DIR}/libwebp-iOS/libwebp.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Expecta.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KVOController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -595,11 +579,13 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; @@ -629,11 +615,13 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; diff --git a/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests Mac.xcscheme b/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests Mac.xcscheme index b9e1b2ab..f051ab77 100644 --- a/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests Mac.xcscheme +++ b/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests Mac.xcscheme @@ -1,6 +1,6 @@ + codeCoverageEnabled = "YES" + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -57,7 +56,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index ea46472f..4b68080d 100644 --- a/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ + codeCoverageEnabled = "YES" + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -48,7 +47,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Tests/Tests/Images/TestImageAnimated.webp b/Tests/Tests/Images/TestImageAnimated.webp deleted file mode 100644 index 5b44046e2c8ca21ac7f5821317dfbcb172334b12..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4764 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 b&&Z-)Og^hE*22=oeg$Y(!iu%s#c=-zAK+%p diff --git a/Tests/Tests/Images/TestImageStatic.webp b/Tests/Tests/Images/TestImageStatic.webp deleted file mode 100644 index 122741b605f3121d393829ffb5b7a0924db13c86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30320 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 TU=pkm8Veub3_|1vJMaJi)t)C5 diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index 13841164..5af4b002 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -29,7 +29,6 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun - (void)tearDown { [[SDImageCache sharedImageCache] removeImageForKey:kTestGIFURL fromDisk:YES withCompletion:nil]; - [[SDImageCache sharedImageCache] removeImageForKey:kTestWebPURL fromDisk:YES withCompletion:nil]; } - (void)test01AnimatedImageInitWithData { @@ -97,14 +96,6 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun expect(imageView.currentFrame).beNil(); // current frame } -- (void)test07AnimatedImageViewSetAnimatedImageWEBP { - SDAnimatedImageView *imageView = [SDAnimatedImageView new]; - SDAnimatedImage *image = [SDAnimatedImage imageWithData:[self testAnimatedWebPData]]; - imageView.image = image; - expect(imageView.image).notTo.beNil(); - expect(imageView.currentFrame).notTo.beNil(); // current frame -} - - (void)test08AnimatedImageViewSetAnimatedImageGIF { SDAnimatedImageView *imageView = [SDAnimatedImageView new]; SDAnimatedImage *image = [SDAnimatedImage imageWithData:[self testGIFData]]; @@ -210,7 +201,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun - (void)test22AnimatedImageViewCategory { XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"]; SDAnimatedImageView *imageView = [SDAnimatedImageView new]; - NSURL *testURL = [NSURL URLWithString:kTestWebPURL]; + NSURL *testURL = [NSURL URLWithString:kTestGIFURL]; [imageView sd_setImageWithURL:testURL completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { expect(error).to.beNil(); expect(image).notTo.beNil(); @@ -268,16 +259,6 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun return testData; } -- (NSString *)testAnimatedWebPPath { - NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; - NSString *testPath = [testBundle pathForResource:@"TestImageAnimated" ofType:@"webp"]; - return testPath; -} - -- (NSData *)testAnimatedWebPData { - return [NSData dataWithContentsOfFile:[self testAnimatedWebPPath]]; -} - - (NSString *)testAPNGPPath { NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; NSString *testPath = [testBundle pathForResource:@"TestImageAnimated" ofType:@"apng"]; diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m index 35233945..08415834 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDCategoriesTests.m @@ -51,16 +51,6 @@ expect(image).notTo.beNil(); } -- (void)test04UIImageWebPCategory { - // Test invalid image data - UIImage *image = [UIImage sd_imageWithWebPData:nil]; - expect(image).to.beNil(); - // Test valid image data - NSData *data = [NSData dataWithContentsOfFile:[self testWebPPath]]; - image = [UIImage sd_imageWithWebPData:data]; - expect(image).notTo.beNil(); -} - #pragma mark - Helper - (NSString *)testJPEGPath { @@ -73,9 +63,4 @@ return [testBundle pathForResource:@"TestImage" ofType:@"gif"]; } -- (NSString *)testWebPPath { - NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; - return [testBundle pathForResource:@"TestImageStatic" ofType:@"webp"]; -} - @end diff --git a/Tests/Tests/SDImageCoderTests.m b/Tests/Tests/SDImageCoderTests.m index c8d606fa..e4caa48f 100644 --- a/Tests/Tests/SDImageCoderTests.m +++ b/Tests/Tests/SDImageCoderTests.m @@ -79,26 +79,10 @@ } #endif -- (void)test09ThatStaticWebPCoderWorks { - NSURL *staticWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageStatic" withExtension:@"webp"]; - [self verifyCoder:[SDImageWebPCoder sharedCoder] - withLocalImageURL:staticWebPURL - supportsEncoding:YES - isAnimatedImage:NO]; -} - -- (void)test10ThatAnimatedWebPCoderWorks { - NSURL *animatedWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageAnimated" withExtension:@"webp"]; - [self verifyCoder:[SDImageWebPCoder sharedCoder] - withLocalImageURL:animatedWebPURL - supportsEncoding:YES - isAnimatedImage:YES]; -} - - (void)test11ThatAPNGPCoderWorks { - NSURL *animatedWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageAnimated" withExtension:@"apng"]; + NSURL *APNGURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageAnimated" withExtension:@"apng"]; [self verifyCoder:[SDImageAPNGCoder sharedCoder] - withLocalImageURL:animatedWebPURL + withLocalImageURL:APNGURL supportsEncoding:YES isAnimatedImage:YES]; } diff --git a/Tests/Tests/SDTestCase.h b/Tests/Tests/SDTestCase.h index 7f28d3fa..2421d990 100644 --- a/Tests/Tests/SDTestCase.h +++ b/Tests/Tests/SDTestCase.h @@ -25,7 +25,6 @@ FOUNDATION_EXPORT NSString * _Nonnull const kTestJPEGURL; FOUNDATION_EXPORT NSString * _Nonnull const kTestProgressiveJPEGURL; FOUNDATION_EXPORT NSString * _Nonnull const kTestPNGURL; FOUNDATION_EXPORT NSString * _Nonnull const kTestGIFURL; -FOUNDATION_EXPORT NSString * _Nonnull const kTestWebPURL; FOUNDATION_EXPORT NSString * _Nonnull const kTestAPNGPURL; @interface SDTestCase : XCTestCase diff --git a/Tests/Tests/SDTestCase.m b/Tests/Tests/SDTestCase.m index a635caae..c86bae01 100644 --- a/Tests/Tests/SDTestCase.m +++ b/Tests/Tests/SDTestCase.m @@ -15,7 +15,6 @@ NSString *const kTestJPEGURL = @"http://via.placeholder.com/50x50.jpg"; NSString *const kTestProgressiveJPEGURL = @"https://raw.githubusercontent.com/ibireme/YYImage/master/Demo/YYImageDemo/mew_progressive.jpg"; NSString *const kTestPNGURL = @"http://via.placeholder.com/50x50.png"; NSString *const kTestGIFURL = @"https://media.giphy.com/media/UEsrLdv7ugRTq/giphy.gif"; -NSString *const kTestWebPURL = @"http://littlesvr.ca/apng/images/SteamEngine.webp"; NSString *const kTestAPNGPURL = @"https://upload.wikimedia.org/wikipedia/commons/1/14/Animated_PNG_example_bouncing_beach_ball.png"; @implementation SDTestCase diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index bcb0e629..9c328344 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -231,34 +231,6 @@ [self waitForExpectationsWithCommonTimeout]; } -- (void)test15ThatWEBPWorks { - XCTestExpectation *expectation = [self expectationWithDescription:@"WEBP"]; - NSURL *imageURL = [NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp"]; - [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { - if (image && data && !error && finished) { - [expectation fulfill]; - } else { - XCTFail(@"Something went wrong"); - } - }]; - [self waitForExpectationsWithCommonTimeout]; -} - -- (void)test16ThatProgressiveWebPWorks { - XCTestExpectation *expectation = [self expectationWithDescription:@"Progressive WebP download"]; - NSURL *imageURL = [NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test9.webp"]; - [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:SDWebImageDownloaderProgressiveLoad progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { - if (image && data && !error && finished) { - [expectation fulfill]; - } else if (finished) { - XCTFail(@"Something went wrong"); - } else { - // progressive updates - } - }]; - [self waitForExpectationsWithCommonTimeout]; -} - - (void)test17ThatMinimumProgressIntervalWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Minimum progress interval"]; SDWebImageDownloaderConfig *config = SDWebImageDownloaderConfig.defaultDownloaderConfig; diff --git a/Vendors/libwebp b/Vendors/libwebp deleted file mode 160000 index 50d1a848..00000000 --- a/Vendors/libwebp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 50d1a848bc56554af8413cfe681f94286a6371b3 diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index e38da0a2..ce50a1f3 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -80,9 +80,3 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #if __has_include() #import #endif - -// WebP -#if __has_include() -#import -#import -#endif From 735bbf6f8cfbee9aab0f0640d1cb1224354c70fc Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Mon, 10 Sep 2018 16:21:07 +0800 Subject: [PATCH 271/361] Remove input/outputFileListPaths attributes in Xcodeproj --- Examples/SDWebImage Demo.xcodeproj/project.pbxproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Examples/SDWebImage Demo.xcodeproj/project.pbxproj b/Examples/SDWebImage Demo.xcodeproj/project.pbxproj index 325e3114..e3139c4f 100644 --- a/Examples/SDWebImage Demo.xcodeproj/project.pbxproj +++ b/Examples/SDWebImage Demo.xcodeproj/project.pbxproj @@ -636,15 +636,11 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-SDWebImage Watch Demo Extension-checkManifestLockResult.txt", ); @@ -716,8 +712,6 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension-frameworks.sh", "${BUILT_PRODUCTS_DIR}/SDWebImage-watchOS/SDWebImage.framework", @@ -725,8 +719,6 @@ "${BUILT_PRODUCTS_DIR}/libwebp-watchOS/libwebp.framework", ); name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - ); outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", From ae552f9350120872e77ec1cedfebf2586b84d819 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Fri, 7 Sep 2018 16:54:18 +0300 Subject: [PATCH 272/361] Merged SDWebImage iOS + SDWebImage OSX + SDWebImage tvOS + SDWebImage watchOS targets into SDWebImage target (supports all platforms) Merged SDWebImage iOS static + SDWebImage watchOS static targets into SDWebImage static target (supports all platforms) Created dedicated SDWebImageMapKit target All this is done for: - ability to install via Carthage without MapKit dependency now we generate SDWebImage.framework and SDWebImageMapKit.framework so the users can choose to link against core or core+MapKit. - simpler management of targets (no need to duplicate effort). Replacement for #2078 Merged SDWebImage iOS + SDWebImage OSX + SDWebImage tvOS + SDWebImage watchOS targets into SDWebImage target (supports all platforms) Merged SDWebImage iOS static + SDWebImage watchOS static targets into SDWebImage static target (supports all platforms) Created dedicated SDWebImageMapKit target All this is done for: - ability to install via Carthage without MapKit dependency now we generate SDWebImage.framework and SDWebImageMapKit.framework so the users can choose to link against core or core+MapKit. - simpler management of targets (no need to duplicate effort). Replacement for #2078 --- .travis.yml | 22 +- .../xcschemes/SDWebImage iOS Demo.xcscheme | 8 +- README.md | 11 +- SDWebImage.xcodeproj/project.pbxproj | 1422 +++-------------- ...ic.xcscheme => SDWebImage static.xcscheme} | 8 +- .../xcschemes/SDWebImage tvOS.xcscheme | 80 - .../SDWebImage watchOS static.xcscheme | 80 - .../xcschemes/SDWebImage watchOS.xcscheme | 80 - ...Image iOS.xcscheme => SDWebImage.xcscheme} | 6 +- ...OSX.xcscheme => SDWebImageMapKit.xcscheme} | 18 +- WebImage/SDWebImageMapKit.h | 21 + 11 files changed, 237 insertions(+), 1519 deletions(-) rename {SDWebImage.xcworkspace => Examples/SDWebImage Demo.xcodeproj}/xcshareddata/xcschemes/SDWebImage iOS Demo.xcscheme (91%) rename SDWebImage.xcodeproj/xcshareddata/xcschemes/{SDWebImage iOS static.xcscheme => SDWebImage static.xcscheme} (91%) delete mode 100644 SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage tvOS.xcscheme delete mode 100644 SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS static.xcscheme delete mode 100644 SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS.xcscheme rename SDWebImage.xcodeproj/xcshareddata/xcschemes/{SDWebImage iOS.xcscheme => SDWebImage.xcscheme} (95%) rename SDWebImage.xcodeproj/xcshareddata/xcschemes/{SDWebImage OSX.xcscheme => SDWebImageMapKit.xcscheme} (82%) create mode 100644 WebImage/SDWebImageMapKit.h diff --git a/.travis.yml b/.travis.yml index 96d36964..6f536f4f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,17 +29,17 @@ script: - pod lib lint --allow-warnings - echo Build as static library - - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS static' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c - - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS static' -sdk watchsimulator -configuration Debug | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage static' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage static' -sdk watchsimulator -configuration Debug | xcpretty -c - - echo Build as dynamic framework - - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX' -sdk macosx -configuration Debug | xcpretty -c - - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c - - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage tvOS' -sdk appletvsimulator -configuration Debug | xcpretty -c - - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS' -sdk watchsimulator -configuration Debug | xcpretty -c - - - echo Clean DerivedData - - rm -rf ~/Library/Developer/Xcode/DerivedData + - echo Build as dynamic frameworks + - xcodebuild build clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage' -sdk macosx -configuration Debug | xcpretty -c + - xcodebuild build clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c + - xcodebuild build clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage' -sdk appletvsimulator -configuration Debug | xcpretty -c + - xcodebuild build clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage' -sdk watchsimulator -configuration Debug | xcpretty -c + - xcodebuild build clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImageMapKit' -sdk macosx -configuration Debug | xcpretty -c + - xcodebuild build clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImageMapKit' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c + - xcodebuild build clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImageMapKit' -sdk appletvsimulator -configuration Debug | xcpretty -c - echo Build the Demo apps - pod install --project-directory=Examples @@ -48,9 +48,7 @@ script: - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage TV Demo' -sdk appletvsimulator -configuration Debug | xcpretty -c - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone 8' | xcpretty -c - - echo Clean DerivedData - mkdir DerivedData - - rm -rf ~/Library/Developer/Xcode/DerivedData - echo Run the tests - pod install --project-directory=Tests diff --git a/SDWebImage.xcworkspace/xcshareddata/xcschemes/SDWebImage iOS Demo.xcscheme b/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS Demo.xcscheme similarity index 91% rename from SDWebImage.xcworkspace/xcshareddata/xcschemes/SDWebImage iOS Demo.xcscheme rename to Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS Demo.xcscheme index e4a3bb64..60cadc19 100644 --- a/SDWebImage.xcworkspace/xcshareddata/xcschemes/SDWebImage iOS Demo.xcscheme +++ b/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS Demo.xcscheme @@ -17,7 +17,7 @@ BlueprintIdentifier = "53761294155AB74D005750A4" BuildableName = "SDWebImage iOS Demo.app" BlueprintName = "SDWebImage iOS Demo" - ReferencedContainer = "container:Examples/SDWebImage Demo.xcodeproj"> + ReferencedContainer = "container:SDWebImage Demo.xcodeproj"> @@ -35,7 +35,7 @@ BlueprintIdentifier = "53761294155AB74D005750A4" BuildableName = "SDWebImage iOS Demo.app" BlueprintName = "SDWebImage iOS Demo" - ReferencedContainer = "container:Examples/SDWebImage Demo.xcodeproj"> + ReferencedContainer = "container:SDWebImage Demo.xcodeproj"> @@ -58,7 +58,7 @@ BlueprintIdentifier = "53761294155AB74D005750A4" BuildableName = "SDWebImage iOS Demo.app" BlueprintName = "SDWebImage iOS Demo" - ReferencedContainer = "container:Examples/SDWebImage Demo.xcodeproj"> + ReferencedContainer = "container:SDWebImage Demo.xcodeproj"> @@ -84,7 +84,7 @@ BlueprintIdentifier = "53761294155AB74D005750A4" BuildableName = "SDWebImage iOS Demo.app" BlueprintName = "SDWebImage iOS Demo" - ReferencedContainer = "container:Examples/SDWebImage Demo.xcodeproj"> + ReferencedContainer = "container:SDWebImage Demo.xcodeproj"> diff --git a/README.md b/README.md index 90800a4e..7f75e3ad 100644 --- a/README.md +++ b/README.md @@ -163,10 +163,13 @@ pod 'SDWebImage/MapKit' To install with carthage, follow the instruction on [Carthage](https://github.com/Carthage/Carthage) -#### Cartfile -``` -github "rs/SDWebImage" -``` +Carthage users can point to this repository and use whichever generated framework they'd like: SDWebImage, SDWebImageMapKit or both. + +Make the following entry in your Cartfile: `github "rs/SDWebImage"` +Then run `carthage update` +If this is your first time using Carthage in the project, you'll need to go through some additional steps as explained [over at Carthage](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application). + +> NOTE: At this time, Carthage does not provide a way to build only specific repository subcomponents (or equivalent of CocoaPods's subspecs). All components and their dependencies will be built with the above command. However, you don't need to copy frameworks you aren't using into your project. For instance, if you aren't using `SDWebImageMapKit`, feel free to delete that framework from the Carthage Build directory after `carthage update` completes. ### Installation by cloning the repository - see [Manual install](https://raw.githubusercontent.com/rs/SDWebImage/master/Docs/ManualInstallation.md) diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 0e1a5c28..c2186d66 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -7,494 +7,127 @@ objects = { /* Begin PBXBuildFile section */ - 00733A541BC4880000A5A117 /* SDWebImageCompat.m in Sources */ = {isa = PBXBuildFile; fileRef = 5340674F167780C40042B59E /* SDWebImageCompat.m */; }; - 00733A551BC4880000A5A117 /* SDWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8C148C56230056699D /* SDWebImageDownloader.m */; }; - 00733A561BC4880000A5A117 /* SDWebImageDownloaderOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 530E49E416460AE2002868E7 /* SDWebImageDownloaderOperation.m */; }; - 00733A571BC4880000A5A117 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D86148C56230056699D /* SDImageCache.m */; }; - 00733A581BC4880000A5A117 /* SDWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8F148C56230056699D /* SDWebImageManager.m */; }; - 00733A5A1BC4880000A5A117 /* SDWebImagePrefetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D92148C56230056699D /* SDWebImagePrefetcher.m */; }; - 00733A5B1BC4880000A5A117 /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */; }; - 00733A5C1BC4880000A5A117 /* UIButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D94148C56230056699D /* UIButton+WebCache.m */; }; - 00733A5D1BC4880000A5A117 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = A18A6CC6172DC28500419892 /* UIImage+GIF.m */; }; - 00733A5E1BC4880000A5A117 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */; }; - 00733A601BC4880000A5A117 /* UIImageView+HighlightedWebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */; }; - 00733A611BC4880000A5A117 /* UIImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D96148C56230056699D /* UIImageView+WebCache.m */; }; - 00733A621BC4880000A5A117 /* UIView+WebCacheOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AB615302192DA24600A2D8E9 /* UIView+WebCacheOperation.m */; }; - 00733A631BC4880E00A5A117 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D88148C56230056699D /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A641BC4880E00A5A117 /* SDWebImageOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 530E49E71646388E002868E7 /* SDWebImageOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A651BC4880E00A5A117 /* SDWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8B148C56230056699D /* SDWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A661BC4880E00A5A117 /* SDWebImageDownloaderOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 530E49E316460AE2002868E7 /* SDWebImageDownloaderOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A671BC4880E00A5A117 /* SDImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D85148C56230056699D /* SDImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A681BC4880E00A5A117 /* SDWebImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8E148C56230056699D /* SDWebImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A6A1BC4880E00A5A117 /* SDWebImagePrefetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D91148C56230056699D /* SDWebImagePrefetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A6B1BC4880E00A5A117 /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A6C1BC4880E00A5A117 /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D93148C56230056699D /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A6D1BC4880E00A5A117 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A6E1BC4880E00A5A117 /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A701BC4880E00A5A117 /* UIImageView+HighlightedWebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = ABBE71A518C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A711BC4880E00A5A117 /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D95148C56230056699D /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A721BC4880E00A5A117 /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A731BC4880E00A5A117 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 320224BB203979BA00E9F285 /* SDAnimatedImageRep.h in Headers */ = {isa = PBXBuildFile; fileRef = 320224B9203979BA00E9F285 /* SDAnimatedImageRep.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 320224BC203979BA00E9F285 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; 320CAE152086F50500CFFC80 /* SDWebImageError.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CAE132086F50500CFFC80 /* SDWebImageError.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 320CAE162086F50500CFFC80 /* SDWebImageError.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CAE132086F50500CFFC80 /* SDWebImageError.h */; settings = {ATTRIBUTES = (Public, ); }; }; 320CAE172086F50500CFFC80 /* SDWebImageError.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CAE132086F50500CFFC80 /* SDWebImageError.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 320CAE182086F50500CFFC80 /* SDWebImageError.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CAE132086F50500CFFC80 /* SDWebImageError.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 320CAE192086F50500CFFC80 /* SDWebImageError.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CAE132086F50500CFFC80 /* SDWebImageError.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 320CAE1A2086F50500CFFC80 /* SDWebImageError.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CAE132086F50500CFFC80 /* SDWebImageError.h */; settings = {ATTRIBUTES = (Public, ); }; }; 320CAE1B2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; - 320CAE1C2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; 320CAE1D2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; - 320CAE1E2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; - 320CAE1F2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; - 320CAE202086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; 321B37812083290E00C0EA77 /* SDImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37822083290E00C0EA77 /* SDImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321B37832083290E00C0EA77 /* SDImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37842083290E00C0EA77 /* SDImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37852083290E00C0EA77 /* SDImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37862083290E00C0EA77 /* SDImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321B37872083290E00C0EA77 /* SDImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDImageLoader.m */; }; - 321B37882083290E00C0EA77 /* SDImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDImageLoader.m */; }; 321B37892083290E00C0EA77 /* SDImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDImageLoader.m */; }; - 321B378A2083290E00C0EA77 /* SDImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDImageLoader.m */; }; - 321B378B2083290E00C0EA77 /* SDImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDImageLoader.m */; }; - 321B378C2083290E00C0EA77 /* SDImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDImageLoader.m */; }; 321B378D2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B378E2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321B378F2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37902083290E00C0EA77 /* SDImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37912083290E00C0EA77 /* SDImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37922083290E00C0EA77 /* SDImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321B37932083290E00C0EA77 /* SDImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDImageLoadersManager.m */; }; - 321B37942083290E00C0EA77 /* SDImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDImageLoadersManager.m */; }; 321B37952083290E00C0EA77 /* SDImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDImageLoadersManager.m */; }; - 321B37962083290E00C0EA77 /* SDImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDImageLoadersManager.m */; }; - 321B37972083290E00C0EA77 /* SDImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDImageLoadersManager.m */; }; - 321B37982083290E00C0EA77 /* SDImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDImageLoadersManager.m */; }; - 321DB3612011D4D70015D2CB /* NSButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321DB3622011D4D70015D2CB /* NSButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */; }; 321E60861F38E8C800405457 /* SDImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60871F38E8C800405457 /* SDImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321E60881F38E8C800405457 /* SDImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60891F38E8C800405457 /* SDImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E608A1F38E8C800405457 /* SDImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E608B1F38E8C800405457 /* SDImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321E608C1F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; - 321E608D1F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; 321E608E1F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; - 321E608F1F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; - 321E60901F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; - 321E60911F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; 321E60941F38E8ED00405457 /* SDImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60951F38E8ED00405457 /* SDImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321E60961F38E8ED00405457 /* SDImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60971F38E8ED00405457 /* SDImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60981F38E8ED00405457 /* SDImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60991F38E8ED00405457 /* SDImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321E609A1F38E8ED00405457 /* SDImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDImageIOCoder.m */; }; - 321E609B1F38E8ED00405457 /* SDImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDImageIOCoder.m */; }; 321E609C1F38E8ED00405457 /* SDImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDImageIOCoder.m */; }; - 321E609D1F38E8ED00405457 /* SDImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDImageIOCoder.m */; }; - 321E609E1F38E8ED00405457 /* SDImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDImageIOCoder.m */; }; - 321E609F1F38E8ED00405457 /* SDImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDImageIOCoder.m */; }; 321E60A21F38E8F600405457 /* SDImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60A31F38E8F600405457 /* SDImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321E60A41F38E8F600405457 /* SDImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60A51F38E8F600405457 /* SDImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60A61F38E8F600405457 /* SDImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60A71F38E8F600405457 /* SDImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321E60A81F38E8F600405457 /* SDImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */; }; - 321E60A91F38E8F600405457 /* SDImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */; }; 321E60AA1F38E8F600405457 /* SDImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */; }; - 321E60AB1F38E8F600405457 /* SDImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */; }; - 321E60AC1F38E8F600405457 /* SDImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */; }; - 321E60AD1F38E8F600405457 /* SDImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */; }; 321E60BE1F38E91700405457 /* UIImage+ForceDecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60BF1F38E91700405457 /* UIImage+ForceDecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321E60C01F38E91700405457 /* UIImage+ForceDecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60C11F38E91700405457 /* UIImage+ForceDecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60C21F38E91700405457 /* UIImage+ForceDecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60C31F38E91700405457 /* UIImage+ForceDecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321E60C41F38E91700405457 /* UIImage+ForceDecode.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */; }; - 321E60C51F38E91700405457 /* UIImage+ForceDecode.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */; }; 321E60C61F38E91700405457 /* UIImage+ForceDecode.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */; }; - 321E60C71F38E91700405457 /* UIImage+ForceDecode.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */; }; - 321E60C81F38E91700405457 /* UIImage+ForceDecode.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */; }; - 321E60C91F38E91700405457 /* UIImage+ForceDecode.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */; }; 3237F9E820161AE000A88143 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; - 3237F9E920161AE000A88143 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; - 3237F9EA20161AE000A88143 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; 3237F9EB20161AE000A88143 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; - 3237F9EC20161AE000A88143 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; 3248475D201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; - 3248475E201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; 3248475F201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; - 32484760201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; - 32484761201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; - 32484762201775F600AF9E5A /* SDAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32484757201775F600AF9E5A /* SDAnimatedImageView.m */; }; 32484763201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32484764201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32484765201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32484766201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32484767201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32484768201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32484769201775F600AF9E5A /* SDAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484759201775F600AF9E5A /* SDAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3248476A201775F600AF9E5A /* SDAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484759201775F600AF9E5A /* SDAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3248476B201775F600AF9E5A /* SDAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484759201775F600AF9E5A /* SDAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3248476C201775F600AF9E5A /* SDAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484759201775F600AF9E5A /* SDAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3248476D201775F600AF9E5A /* SDAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484759201775F600AF9E5A /* SDAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3248476E201775F600AF9E5A /* SDAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 32484759201775F600AF9E5A /* SDAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3248476F201775F600AF9E5A /* SDAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475A201775F600AF9E5A /* SDAnimatedImage.m */; }; - 32484770201775F600AF9E5A /* SDAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475A201775F600AF9E5A /* SDAnimatedImage.m */; }; 32484771201775F600AF9E5A /* SDAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475A201775F600AF9E5A /* SDAnimatedImage.m */; }; - 32484772201775F600AF9E5A /* SDAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475A201775F600AF9E5A /* SDAnimatedImage.m */; }; - 32484773201775F600AF9E5A /* SDAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475A201775F600AF9E5A /* SDAnimatedImage.m */; }; - 32484774201775F600AF9E5A /* SDAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475A201775F600AF9E5A /* SDAnimatedImage.m */; }; 32484775201775F600AF9E5A /* SDAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3248475B201775F600AF9E5A /* SDAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32484776201775F600AF9E5A /* SDAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3248475B201775F600AF9E5A /* SDAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32484777201775F600AF9E5A /* SDAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3248475B201775F600AF9E5A /* SDAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32484778201775F600AF9E5A /* SDAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3248475B201775F600AF9E5A /* SDAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32484779201775F600AF9E5A /* SDAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3248475B201775F600AF9E5A /* SDAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3248477A201775F600AF9E5A /* SDAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3248475B201775F600AF9E5A /* SDAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3248477B201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */; }; - 3248477C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */; }; 3248477D201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */; }; - 3248477E201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */; }; - 3248477F201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */; }; - 32484780201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */; }; 324DF4B4200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 324DF4B5200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; 324DF4B6200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 324DF4B7200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 324DF4B8200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 324DF4B9200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; 324DF4BA200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; }; - 324DF4BB200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; }; 324DF4BC200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; }; - 324DF4BD200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; }; - 324DF4BE200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; }; - 324DF4BF200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; }; 325312C8200F09910046BF1E /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 325312C6200F09910046BF1E /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 325312C9200F09910046BF1E /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 325312C6200F09910046BF1E /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; }; 325312CA200F09910046BF1E /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 325312C6200F09910046BF1E /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 325312CB200F09910046BF1E /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 325312C6200F09910046BF1E /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 325312CC200F09910046BF1E /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 325312C6200F09910046BF1E /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 325312CD200F09910046BF1E /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 325312C6200F09910046BF1E /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; }; 325312CE200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; }; - 325312CF200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; }; 325312D0200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; }; - 325312D1200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; }; - 325312D2200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; }; - 325312D3200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; }; 327054D4206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 327054D5206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 327054D6206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 327054D7206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 327054D8206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 327054D9206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 327054DA206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; }; - 327054DB206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; }; 327054DC206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; }; - 327054DD206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; }; - 327054DE206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; }; - 327054DF206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; }; 328BB69C2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB69D2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 328BB69E2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB69F2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB6A02081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB6A12081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 328BB6A22081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */; }; - 328BB6A32081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */; }; 328BB6A42081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */; }; - 328BB6A52081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */; }; - 328BB6A62081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */; }; - 328BB6A72081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */; }; 328BB6AA2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB6AB2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 328BB6AC2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB6AD2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB6AE2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB6AF2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 328BB6B02081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6A92081FEE500760D6C /* SDWebImageCacheSerializer.m */; }; - 328BB6B12081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6A92081FEE500760D6C /* SDWebImageCacheSerializer.m */; }; 328BB6B22081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6A92081FEE500760D6C /* SDWebImageCacheSerializer.m */; }; - 328BB6B32081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6A92081FEE500760D6C /* SDWebImageCacheSerializer.m */; }; - 328BB6B42081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6A92081FEE500760D6C /* SDWebImageCacheSerializer.m */; }; - 328BB6B52081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6A92081FEE500760D6C /* SDWebImageCacheSerializer.m */; }; 328BB6C12082581100760D6C /* SDDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BD2082581100760D6C /* SDDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB6C22082581100760D6C /* SDDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BD2082581100760D6C /* SDDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 328BB6C32082581100760D6C /* SDDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BD2082581100760D6C /* SDDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB6C42082581100760D6C /* SDDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BD2082581100760D6C /* SDDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB6C52082581100760D6C /* SDDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BD2082581100760D6C /* SDDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB6C62082581100760D6C /* SDDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BD2082581100760D6C /* SDDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 328BB6C72082581100760D6C /* SDDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6BE2082581100760D6C /* SDDiskCache.m */; }; - 328BB6C82082581100760D6C /* SDDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6BE2082581100760D6C /* SDDiskCache.m */; }; 328BB6C92082581100760D6C /* SDDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6BE2082581100760D6C /* SDDiskCache.m */; }; - 328BB6CA2082581100760D6C /* SDDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6BE2082581100760D6C /* SDDiskCache.m */; }; - 328BB6CB2082581100760D6C /* SDDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6BE2082581100760D6C /* SDDiskCache.m */; }; - 328BB6CC2082581100760D6C /* SDDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6BE2082581100760D6C /* SDDiskCache.m */; }; 328BB6CD2082581100760D6C /* SDMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BF2082581100760D6C /* SDMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB6CE2082581100760D6C /* SDMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BF2082581100760D6C /* SDMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 328BB6CF2082581100760D6C /* SDMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BF2082581100760D6C /* SDMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB6D02082581100760D6C /* SDMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BF2082581100760D6C /* SDMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB6D12082581100760D6C /* SDMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BF2082581100760D6C /* SDMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 328BB6D22082581100760D6C /* SDMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BF2082581100760D6C /* SDMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 328BB6D32082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; - 328BB6D42082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; 328BB6D52082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; - 328BB6D62082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; - 328BB6D72082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; - 328BB6D82082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; 3290FA041FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3290FA051FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3290FA061FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3290FA071FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3290FA081FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3290FA091FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3290FA0A1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; - 3290FA0B1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; 3290FA0C1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; - 3290FA0D1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; - 3290FA0E1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; - 3290FA0F1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; 329A18591FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 329A185A1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; 329A185B1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 329A185C1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 329A185D1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 329A185E1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; 329A185F1FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; - 329A18601FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; 329A18611FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; - 329A18621FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; - 329A18631FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; - 329A18641FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; 32B9B537206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32B9B538206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32B9B53A206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32B9B53B206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32B9B53C206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32B9B53D206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */; }; - 32B9B53E206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */; }; 32B9B53F206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */; }; - 32B9B540206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */; }; - 32B9B541206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */; }; - 32B9B542206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */; }; 32C0FDE12013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32C0FDE22013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32C0FDE32013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32C0FDE42013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32C0FDE52013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32C0FDE62013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32C0FDE72013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; - 32C0FDE82013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; 32C0FDE92013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; - 32C0FDEA2013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; - 32C0FDEB2013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; - 32C0FDEC2013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; 32CF1C071FA496B000004BD1 /* SDImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32CF1C081FA496B000004BD1 /* SDImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32CF1C091FA496B000004BD1 /* SDImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32CF1C0A1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32CF1C0B1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32CF1C0C1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32CF1C0D1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */; }; - 32CF1C0E1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */; }; 32CF1C0F1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */; }; - 32CF1C101FA496B000004BD1 /* SDImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */; }; - 32CF1C111FA496B000004BD1 /* SDImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */; }; - 32CF1C121FA496B000004BD1 /* SDImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */; }; 32D1221E2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D1221F2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32D122202080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122212080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122222080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122232080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32D122242080B2EB003685A3 /* SDImageCacheDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */; }; - 32D122252080B2EB003685A3 /* SDImageCacheDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */; }; 32D122262080B2EB003685A3 /* SDImageCacheDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */; }; - 32D122272080B2EB003685A3 /* SDImageCacheDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */; }; - 32D122282080B2EB003685A3 /* SDImageCacheDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */; }; - 32D122292080B2EB003685A3 /* SDImageCacheDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */; }; 32D1222A2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; - 32D1222B2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; 32D1222C2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; - 32D1222D2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; - 32D1222E2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; - 32D1222F2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; 32D122302080B2EB003685A3 /* SDImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122312080B2EB003685A3 /* SDImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32D122322080B2EB003685A3 /* SDImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122332080B2EB003685A3 /* SDImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122342080B2EB003685A3 /* SDImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122352080B2EB003685A3 /* SDImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32EB6D8E206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; - 32EB6D8F206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; - 32EB6D90206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; 32EB6D91206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; - 32EB6D92206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; 32F21B5120788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F21B5220788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32F21B5320788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F21B5420788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F21B5520788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F21B5620788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32F21B5720788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; - 32F21B5820788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; 32F21B5920788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; - 32F21B5A20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; - 32F21B5B20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; - 32F21B5C20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; 32F7C06F2030114C00873181 /* SDImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F7C0702030114C00873181 /* SDImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32F7C0712030114C00873181 /* SDImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F7C0722030114C00873181 /* SDImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F7C0732030114C00873181 /* SDImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F7C0742030114C00873181 /* SDImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32F7C0752030114C00873181 /* SDImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDImageTransformer.m */; }; - 32F7C0762030114C00873181 /* SDImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDImageTransformer.m */; }; 32F7C0772030114C00873181 /* SDImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDImageTransformer.m */; }; - 32F7C0782030114C00873181 /* SDImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDImageTransformer.m */; }; - 32F7C0792030114C00873181 /* SDImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDImageTransformer.m */; }; - 32F7C07A2030114C00873181 /* SDImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDImageTransformer.m */; }; 32F7C07E2030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; - 32F7C07F2030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; 32F7C0802030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; - 32F7C0812030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; - 32F7C0822030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; - 32F7C0832030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; 32F7C0842030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F7C0852030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32F7C0862030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F7C0872030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F7C0882030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F7C0892030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE87C2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */; }; - 32FDE87D2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */; }; - 32FDE87E2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */; }; - 32FDE87F2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */; }; - 32FDE8802088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE8812088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE8822088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE8832088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32FDE8A220888789008D7530 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE8A320888789008D7530 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D1231D0E0E3B004B36C9 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D86148C56230056699D /* SDImageCache.m */; }; - 4314D1311D0E0E3B004B36C9 /* SDWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8C148C56230056699D /* SDWebImageDownloader.m */; }; - 4314D1361D0E0E3B004B36C9 /* SDWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8F148C56230056699D /* SDWebImageManager.m */; }; - 4314D1371D0E0E3B004B36C9 /* SDWebImagePrefetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D92148C56230056699D /* SDWebImagePrefetcher.m */; }; - 4314D13B1D0E0E3B004B36C9 /* UIButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D94148C56230056699D /* UIButton+WebCache.m */; }; - 4314D1401D0E0E3B004B36C9 /* UIImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D96148C56230056699D /* UIImageView+WebCache.m */; }; - 4314D1411D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 530E49E416460AE2002868E7 /* SDWebImageDownloaderOperation.m */; }; - 4314D14B1D0E0E3B004B36C9 /* SDWebImageCompat.m in Sources */ = {isa = PBXBuildFile; fileRef = 5340674F167780C40042B59E /* SDWebImageCompat.m */; }; - 4314D14D1D0E0E3B004B36C9 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = A18A6CC6172DC28500419892 /* UIImage+GIF.m */; }; - 4314D1501D0E0E3B004B36C9 /* UIView+WebCacheOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AB615302192DA24600A2D8E9 /* UIView+WebCacheOperation.m */; }; - 4314D1521D0E0E3B004B36C9 /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */; }; - 4314D1531D0E0E3B004B36C9 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */; }; - 4314D1551D0E0E3B004B36C9 /* UIImageView+HighlightedWebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */; }; - 4314D15E1D0E0E3B004B36C9 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53FB894814D35E9E0020B787 /* UIKit.framework */; }; - 4314D15F1D0E0E3B004B36C9 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53922D72148C55820056699D /* Foundation.framework */; }; - 4314D1601D0E0E3B004B36C9 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53FB893F14D35D1A0020B787 /* CoreGraphics.framework */; }; - 4314D16D1D0E0E3B004B36C9 /* SDImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D85148C56230056699D /* SDImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D16F1D0E0E3B004B36C9 /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D1721D0E0E3B004B36C9 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D88148C56230056699D /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D1781D0E0E3B004B36C9 /* SDWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8B148C56230056699D /* SDWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D1791D0E0E3B004B36C9 /* SDWebImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8E148C56230056699D /* SDWebImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D17D1D0E0E3B004B36C9 /* SDWebImagePrefetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D91148C56230056699D /* SDWebImagePrefetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D17F1D0E0E3B004B36C9 /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D93148C56230056699D /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D1811D0E0E3B004B36C9 /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D95148C56230056699D /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D1841D0E0E3B004B36C9 /* SDWebImageOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 530E49E71646388E002868E7 /* SDWebImageOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D1851D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 530E49E316460AE2002868E7 /* SDWebImageDownloaderOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D1861D0E0E3B004B36C9 /* UIImageView+HighlightedWebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = ABBE71A518C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D18F1D0E0E3B004B36C9 /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D1901D0E0E3B004B36C9 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D1921D0E0E3B004B36C9 /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB68C1D06D2C1006A3455 /* SDWebImageDownloaderOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 530E49E416460AE2002868E7 /* SDWebImageDownloaderOperation.m */; }; - 431BB68E1D06D2C1006A3455 /* SDWebImagePrefetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D92148C56230056699D /* SDWebImagePrefetcher.m */; }; - 431BB6921D06D2C1006A3455 /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */; }; - 431BB69A1D06D2C1006A3455 /* SDWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8C148C56230056699D /* SDWebImageDownloader.m */; }; - 431BB6A31D06D2C1006A3455 /* UIImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D96148C56230056699D /* UIImageView+WebCache.m */; }; - 431BB6AA1D06D2C1006A3455 /* SDWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8F148C56230056699D /* SDWebImageManager.m */; }; - 431BB6AC1D06D2C1006A3455 /* SDWebImageCompat.m in Sources */ = {isa = PBXBuildFile; fileRef = 5340674F167780C40042B59E /* SDWebImageCompat.m */; }; - 431BB6B11D06D2C1006A3455 /* UIView+WebCacheOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AB615302192DA24600A2D8E9 /* UIView+WebCacheOperation.m */; }; - 431BB6B91D06D2C1006A3455 /* UIButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D94148C56230056699D /* UIButton+WebCache.m */; }; - 431BB6BD1D06D2C1006A3455 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = A18A6CC6172DC28500419892 /* UIImage+GIF.m */; }; - 431BB6C01D06D2C1006A3455 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D86148C56230056699D /* SDImageCache.m */; }; - 431BB6C41D06D2C1006A3455 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */; }; - 431BB6C71D06D2C1006A3455 /* UIImageView+HighlightedWebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */; }; - 431BB6D91D06D2C1006A3455 /* SDWebImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8E148C56230056699D /* SDWebImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB6DC1D06D2C1006A3455 /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D93148C56230056699D /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB6E11D06D2C1006A3455 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB6E21D06D2C1006A3455 /* UIImageView+HighlightedWebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = ABBE71A518C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB6E31D06D2C1006A3455 /* SDImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D85148C56230056699D /* SDImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB6E61D06D2C1006A3455 /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D95148C56230056699D /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB6E71D06D2C1006A3455 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D88148C56230056699D /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB6E91D06D2C1006A3455 /* SDWebImageDownloaderOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 530E49E316460AE2002868E7 /* SDWebImageDownloaderOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB6EB1D06D2C1006A3455 /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB6EE1D06D2C1006A3455 /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB6EF1D06D2C1006A3455 /* SDWebImagePrefetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D91148C56230056699D /* SDWebImagePrefetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB6F01D06D2C1006A3455 /* SDWebImageOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 530E49E71646388E002868E7 /* SDWebImageOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB6F61D06D2C1006A3455 /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB6F91D06D2C1006A3455 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431BB6FA1D06D2C1006A3455 /* SDWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8B148C56230056699D /* SDWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4369C2771D9807EC007E863A /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4369C2751D9807EC007E863A /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4369C2781D9807EC007E863A /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4369C2751D9807EC007E863A /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4369C2791D9807EC007E863A /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4369C2751D9807EC007E863A /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4369C27A1D9807EC007E863A /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4369C2751D9807EC007E863A /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4369C27B1D9807EC007E863A /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4369C2751D9807EC007E863A /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4369C27C1D9807EC007E863A /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4369C2751D9807EC007E863A /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4369C27E1D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; }; - 4369C27F1D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; }; 4369C2801D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; }; - 4369C2811D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; }; - 4369C2821D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; }; - 4369C2831D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; }; - 4397D27E1D0DDD8C00BB2784 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = A18A6CC6172DC28500419892 /* UIImage+GIF.m */; }; - 4397D28C1D0DDD8C00BB2784 /* UIImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D96148C56230056699D /* UIImageView+WebCache.m */; }; - 4397D28F1D0DDD8C00BB2784 /* SDWebImageDownloaderOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 530E49E416460AE2002868E7 /* SDWebImageDownloaderOperation.m */; }; - 4397D2921D0DDD8C00BB2784 /* SDWebImagePrefetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D92148C56230056699D /* SDWebImagePrefetcher.m */; }; - 4397D2961D0DDD8C00BB2784 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */; }; - 4397D29B1D0DDD8C00BB2784 /* SDWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8C148C56230056699D /* SDWebImageDownloader.m */; }; - 4397D29C1D0DDD8C00BB2784 /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */; }; - 4397D2A11D0DDD8C00BB2784 /* SDWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8F148C56230056699D /* SDWebImageManager.m */; }; - 4397D2A61D0DDD8C00BB2784 /* SDWebImageCompat.m in Sources */ = {isa = PBXBuildFile; fileRef = 5340674F167780C40042B59E /* SDWebImageCompat.m */; }; - 4397D2A81D0DDD8C00BB2784 /* UIButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D94148C56230056699D /* UIButton+WebCache.m */; }; - 4397D2AB1D0DDD8C00BB2784 /* UIView+WebCacheOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AB615302192DA24600A2D8E9 /* UIView+WebCacheOperation.m */; }; - 4397D2AE1D0DDD8C00BB2784 /* UIImageView+HighlightedWebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */; }; - 4397D2B01D0DDD8C00BB2784 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D86148C56230056699D /* SDImageCache.m */; }; - 4397D2C01D0DDD8C00BB2784 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2C31D0DDD8C00BB2784 /* SDWebImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8E148C56230056699D /* SDWebImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2C41D0DDD8C00BB2784 /* SDImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D85148C56230056699D /* SDImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2C51D0DDD8C00BB2784 /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D95148C56230056699D /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2C81D0DDD8C00BB2784 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D88148C56230056699D /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2CB1D0DDD8C00BB2784 /* UIImageView+HighlightedWebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = ABBE71A518C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2D01D0DDD8C00BB2784 /* SDWebImageDownloaderOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 530E49E316460AE2002868E7 /* SDWebImageDownloaderOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2D81D0DDD8C00BB2784 /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D93148C56230056699D /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2D91D0DDD8C00BB2784 /* SDWebImagePrefetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D91148C56230056699D /* SDWebImagePrefetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2DA1D0DDD8C00BB2784 /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2DB1D0DDD8C00BB2784 /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2DC1D0DDD8C00BB2784 /* SDWebImageOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 530E49E71646388E002868E7 /* SDWebImageOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2E11D0DDD8C00BB2784 /* SDWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8B148C56230056699D /* SDWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2EA1D0DDD8C00BB2784 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2EB1D0DDD8C00BB2784 /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2F61D0DE2DF00BB2784 /* NSImage+Compatibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 4397D2F41D0DE2DF00BB2784 /* NSImage+Compatibility.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2F71D0DE2DF00BB2784 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; 43A918641D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43A918651D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; 43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43A918671D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43A918681D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43A918691D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; 43A9186B1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; - 43A9186C1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; 43A9186D1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; - 43A9186E1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; - 43A9186F1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; - 43A918701D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; 4A2CAE041AB4BB5400B6BC39 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4A2CAE181AB4BB6400B6BC39 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D88148C56230056699D /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4A2CAE191AB4BB6400B6BC39 /* SDWebImageCompat.m in Sources */ = {isa = PBXBuildFile; fileRef = 5340674F167780C40042B59E /* SDWebImageCompat.m */; }; @@ -547,18 +180,22 @@ 53EDFB8C17623F7C00698166 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */; }; 5D5B9142188EE8DD006D06BD /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5D5B9145188EE8DD006D06BD /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */; }; + 806BE07C2142C4A200E02143 /* SDWebImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A2CADFF1AB4BB5300B6BC39 /* SDWebImage.framework */; }; + 806BE07E2142C65200E02143 /* SDWebImageMapKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 806BE07D2142C65200E02143 /* SDWebImageMapKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 807A12281F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 807A12291F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 807A122A1F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 807A122B1F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 807A122C1F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 807A122D1F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 807A122E1F89636300EC2A9B /* SDImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDImageCodersManager.m */; }; - 807A122F1F89636300EC2A9B /* SDImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDImageCodersManager.m */; }; 807A12301F89636300EC2A9B /* SDImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDImageCodersManager.m */; }; - 807A12311F89636300EC2A9B /* SDImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDImageCodersManager.m */; }; - 807A12321F89636300EC2A9B /* SDImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDImageCodersManager.m */; }; - 807A12331F89636300EC2A9B /* SDImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDImageCodersManager.m */; }; + 80B6DF7E2142B43300BCB334 /* NSImage+Compatibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 4397D2F41D0DE2DF00BB2784 /* NSImage+Compatibility.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 80B6DF7F2142B43300BCB334 /* NSImage+Compatibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 4397D2F41D0DE2DF00BB2784 /* NSImage+Compatibility.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 80B6DF802142B43A00BCB334 /* SDAnimatedImageRep.h in Headers */ = {isa = PBXBuildFile; fileRef = 320224B9203979BA00E9F285 /* SDAnimatedImageRep.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 80B6DF812142B43B00BCB334 /* SDAnimatedImageRep.h in Headers */ = {isa = PBXBuildFile; fileRef = 320224B9203979BA00E9F285 /* SDAnimatedImageRep.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 80B6DF822142B44400BCB334 /* NSButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */; }; + 80B6DF832142B44500BCB334 /* NSButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */; }; + 80B6DF842142B44600BCB334 /* NSButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 80B6DF852142B44700BCB334 /* NSButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 80B6DFA72142B71600BCB334 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */; }; + 80B6DFCD2142B71600BCB334 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; A18A6CC7172DC28500419892 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; A18A6CC9172DC28500419892 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = A18A6CC6172DC28500419892 /* UIImage+GIF.m */; }; AB615303192DA24600A2D8E9 /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -567,8 +204,17 @@ ABBE71A818C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 806BE07F2142C6C400E02143 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 53922D66148C55810056699D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4A2CADFE1AB4BB5300B6BC39; + remoteInfo = SDWebImage; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXFileReference section */ - 00733A4C1BC487C000A5A117 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 320224B9203979BA00E9F285 /* SDAnimatedImageRep.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDAnimatedImageRep.h; sourceTree = ""; }; 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImageRep.m; sourceTree = ""; }; 320CAE132086F50500CFFC80 /* SDWebImageError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageError.h; sourceTree = ""; }; @@ -630,11 +276,8 @@ 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MKAnnotationView+WebCache.m"; sourceTree = ""; }; 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MKAnnotationView+WebCache.h"; sourceTree = ""; }; 32FDE8A4208887A6008D7530 /* SDWebImage.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = SDWebImage.modulemap; sourceTree = ""; }; - 4314D1991D0E0E3B004B36C9 /* libSDWebImage watchOS static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libSDWebImage watchOS static.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 431BB7031D06D2C1006A3455 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4369C2751D9807EC007E863A /* UIView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+WebCache.h"; path = "SDWebImage/UIView+WebCache.h"; sourceTree = ""; }; 4369C2761D9807EC007E863A /* UIView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIView+WebCache.m"; path = "SDWebImage/UIView+WebCache.m"; sourceTree = ""; }; - 4397D2F21D0DDD8C00BB2784 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4397D2F41D0DE2DF00BB2784 /* NSImage+Compatibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImage+Compatibility.h"; sourceTree = ""; }; 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSImage+Compatibility.m"; sourceTree = ""; }; 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageCacheConfig.h; sourceTree = ""; }; @@ -646,7 +289,7 @@ 530E49E416460AE2002868E7 /* SDWebImageDownloaderOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderOperation.m; sourceTree = ""; }; 530E49E71646388E002868E7 /* SDWebImageOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageOperation.h; sourceTree = ""; }; 5340674F167780C40042B59E /* SDWebImageCompat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCompat.m; sourceTree = ""; }; - 53761325155AD0D5005750A4 /* libSDWebImage iOS static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libSDWebImage iOS static.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 53761325155AD0D5005750A4 /* libSDWebImage static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libSDWebImage static.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 53922D72148C55820056699D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 53922D85148C56230056699D /* SDImageCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDImageCache.h; path = SDWebImage/SDImageCache.h; sourceTree = SOURCE_ROOT; }; 53922D86148C56230056699D /* SDImageCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDImageCache.m; path = SDWebImage/SDImageCache.m; sourceTree = SOURCE_ROOT; }; @@ -667,8 +310,11 @@ 53FB894814D35E9E0020B787 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+ImageContentType.h"; sourceTree = ""; }; 5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+ImageContentType.m"; sourceTree = ""; }; + 806BE07D2142C65200E02143 /* SDWebImageMapKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageMapKit.h; sourceTree = ""; }; 807A12261F89636300EC2A9B /* SDImageCodersManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageCodersManager.h; sourceTree = ""; }; 807A12271F89636300EC2A9B /* SDImageCodersManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageCodersManager.m; sourceTree = ""; }; + 80B6DFEE2142B71600BCB334 /* SDWebImageMapKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImageMapKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 80B6DFF12142B77E00BCB334 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; A18A6CC5172DC28500419892 /* UIImage+GIF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+GIF.h"; sourceTree = ""; }; A18A6CC6172DC28500419892 /* UIImage+GIF.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+GIF.m"; sourceTree = ""; }; AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+WebCacheOperation.h"; sourceTree = ""; }; @@ -678,37 +324,6 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 00733A481BC487C000A5A117 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4314D15D1D0E0E3B004B36C9 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 4314D15E1D0E0E3B004B36C9 /* UIKit.framework in Frameworks */, - 4314D15F1D0E0E3B004B36C9 /* Foundation.framework in Frameworks */, - 4314D1601D0E0E3B004B36C9 /* CoreGraphics.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 431BB6CA1D06D2C1006A3455 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4397D2B81D0DDD8C00BB2784 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 4A2CADFB1AB4BB5300B6BC39 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -726,6 +341,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 80B6DFB72142B71600BCB334 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 806BE07C2142C4A200E02143 /* SDWebImage.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -827,6 +450,7 @@ isa = PBXGroup; children = ( 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */, + 806BE07D2142C65200E02143 /* SDWebImageMapKit.h */, 4A2CAE011AB4BB5400B6BC39 /* Supporting Files */, ); path = WebImage; @@ -855,12 +479,9 @@ 53922D70148C55820056699D /* Products */ = { isa = PBXGroup; children = ( - 53761325155AD0D5005750A4 /* libSDWebImage iOS static.a */, + 53761325155AD0D5005750A4 /* libSDWebImage static.a */, 4A2CADFF1AB4BB5300B6BC39 /* SDWebImage.framework */, - 00733A4C1BC487C000A5A117 /* SDWebImage.framework */, - 431BB7031D06D2C1006A3455 /* SDWebImage.framework */, - 4397D2F21D0DDD8C00BB2784 /* SDWebImage.framework */, - 4314D1991D0E0E3B004B36C9 /* libSDWebImage watchOS static.a */, + 80B6DFEE2142B71600BCB334 /* SDWebImageMapKit.framework */, ); name = Products; sourceTree = ""; @@ -868,6 +489,7 @@ 53922D71148C55820056699D /* Frameworks */ = { isa = PBXGroup; children = ( + 80B6DFF12142B77E00BCB334 /* MapKit.framework */, 53FB893F14D35D1A0020B787 /* CoreGraphics.framework */, 53922D72148C55820056699D /* Foundation.framework */, 53FB894814D35E9E0020B787 /* UIKit.framework */, @@ -975,219 +597,6 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 00733A491BC487C000A5A117 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 32D122212080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, - 32B9B53A206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, - 328BB6AD2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, - 321B37902083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, - 329A185C1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, - 4369C27A1D9807EC007E863A /* UIView+WebCache.h in Headers */, - 32F21B5420788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, - 321E60971F38E8ED00405457 /* SDImageIOCoder.h in Headers */, - 43A918671D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, - 327054D7206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, - 3290FA071FA478AF0047D20C /* SDImageFrame.h in Headers */, - 324DF4B7200A14DC008A84CC /* SDWebImageDefine.h in Headers */, - 807A122B1F89636300EC2A9B /* SDImageCodersManager.h in Headers */, - 00733A681BC4880E00A5A117 /* SDWebImageManager.h in Headers */, - 00733A6C1BC4880E00A5A117 /* UIButton+WebCache.h in Headers */, - 320CAE182086F50500CFFC80 /* SDWebImageError.h in Headers */, - 32FDE8822088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, - 00733A731BC4880E00A5A117 /* SDWebImage.h in Headers */, - 328BB6C42082581100760D6C /* SDDiskCache.h in Headers */, - 00733A701BC4880E00A5A117 /* UIImageView+HighlightedWebCache.h in Headers */, - 00733A671BC4880E00A5A117 /* SDImageCache.h in Headers */, - 00733A711BC4880E00A5A117 /* UIImageView+WebCache.h in Headers */, - 00733A631BC4880E00A5A117 /* SDWebImageCompat.h in Headers */, - 00733A661BC4880E00A5A117 /* SDWebImageDownloaderOperation.h in Headers */, - 328BB6D02082581100760D6C /* SDMemoryCache.h in Headers */, - 321E60891F38E8C800405457 /* SDImageCoder.h in Headers */, - 00733A721BC4880E00A5A117 /* UIView+WebCacheOperation.h in Headers */, - 321B37842083290E00C0EA77 /* SDImageLoader.h in Headers */, - 32484778201775F600AF9E5A /* SDAnimatedImage.h in Headers */, - 00733A6B1BC4880E00A5A117 /* NSData+ImageContentType.h in Headers */, - 325312CB200F09910046BF1E /* SDWebImageTransition.h in Headers */, - 00733A6A1BC4880E00A5A117 /* SDWebImagePrefetcher.h in Headers */, - 00733A641BC4880E00A5A117 /* SDWebImageOperation.h in Headers */, - 32484766201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, - 321E60A51F38E8F600405457 /* SDImageGIFCoder.h in Headers */, - 32CF1C0A1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, - 00733A6E1BC4880E00A5A117 /* UIImage+MultiFormat.h in Headers */, - 3248476C201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, - 32D122332080B2EB003685A3 /* SDImageCachesManager.h in Headers */, - 32F7C0872030719600873181 /* UIImage+Transform.h in Headers */, - 32C0FDE42013426C001B8F2D /* SDWebImageIndicator.h in Headers */, - 321E60C11F38E91700405457 /* UIImage+ForceDecode.h in Headers */, - 32F7C0722030114C00873181 /* SDImageTransformer.h in Headers */, - 00733A6D1BC4880E00A5A117 /* UIImage+GIF.h in Headers */, - 00733A651BC4880E00A5A117 /* SDWebImageDownloader.h in Headers */, - 328BB69F2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4314D1611D0E0E3B004B36C9 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 3290FA051FA478AF0047D20C /* SDImageFrame.h in Headers */, - 32D1221F2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, - 327054D5206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, - 328BB6AB2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, - 32B9B538206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, - 321E60BF1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, - 807A12291F89636300EC2A9B /* SDImageCodersManager.h in Headers */, - 32F7C0852030719600873181 /* UIImage+Transform.h in Headers */, - 328BB69D2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, - 32F7C0702030114C00873181 /* SDImageTransformer.h in Headers */, - 32CF1C081FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, - 4314D16D1D0E0E3B004B36C9 /* SDImageCache.h in Headers */, - 329A185A1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, - 4314D16F1D0E0E3B004B36C9 /* NSData+ImageContentType.h in Headers */, - 321B378E2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, - 321E60871F38E8C800405457 /* SDImageCoder.h in Headers */, - 320CAE162086F50500CFFC80 /* SDWebImageError.h in Headers */, - 3248476A201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, - 321E60951F38E8ED00405457 /* SDImageIOCoder.h in Headers */, - 4314D1721D0E0E3B004B36C9 /* SDWebImageCompat.h in Headers */, - 32484776201775F600AF9E5A /* SDAnimatedImage.h in Headers */, - 321B37822083290E00C0EA77 /* SDImageLoader.h in Headers */, - 325312C9200F09910046BF1E /* SDWebImageTransition.h in Headers */, - 32D122312080B2EB003685A3 /* SDImageCachesManager.h in Headers */, - 43A918651D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, - 4314D1781D0E0E3B004B36C9 /* SDWebImageDownloader.h in Headers */, - 32C0FDE22013426C001B8F2D /* SDWebImageIndicator.h in Headers */, - 4314D1791D0E0E3B004B36C9 /* SDWebImageManager.h in Headers */, - 324DF4B5200A14DC008A84CC /* SDWebImageDefine.h in Headers */, - 321E60A31F38E8F600405457 /* SDImageGIFCoder.h in Headers */, - 32FDE8A320888789008D7530 /* SDWebImage.h in Headers */, - 32F21B5220788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, - 4369C2781D9807EC007E863A /* UIView+WebCache.h in Headers */, - 4314D17D1D0E0E3B004B36C9 /* SDWebImagePrefetcher.h in Headers */, - 328BB6CE2082581100760D6C /* SDMemoryCache.h in Headers */, - 4314D17F1D0E0E3B004B36C9 /* UIButton+WebCache.h in Headers */, - 32484764201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, - 4314D1811D0E0E3B004B36C9 /* UIImageView+WebCache.h in Headers */, - 4314D1841D0E0E3B004B36C9 /* SDWebImageOperation.h in Headers */, - 4314D1851D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.h in Headers */, - 4314D1861D0E0E3B004B36C9 /* UIImageView+HighlightedWebCache.h in Headers */, - 328BB6C22082581100760D6C /* SDDiskCache.h in Headers */, - 4314D18F1D0E0E3B004B36C9 /* UIView+WebCacheOperation.h in Headers */, - 4314D1901D0E0E3B004B36C9 /* UIImage+GIF.h in Headers */, - 4314D1921D0E0E3B004B36C9 /* UIImage+MultiFormat.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 431BB6CB1D06D2C1006A3455 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 321B37912083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, - 328BB6A02081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, - 32CF1C0B1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, - 431BB6D91D06D2C1006A3455 /* SDWebImageManager.h in Headers */, - 321E608A1F38E8C800405457 /* SDImageCoder.h in Headers */, - 32484767201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, - 321B37852083290E00C0EA77 /* SDImageLoader.h in Headers */, - 329A185D1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, - 431BB6DC1D06D2C1006A3455 /* UIButton+WebCache.h in Headers */, - 431BB6E11D06D2C1006A3455 /* SDWebImage.h in Headers */, - 431BB6E21D06D2C1006A3455 /* UIImageView+HighlightedWebCache.h in Headers */, - 321E60C21F38E91700405457 /* UIImage+ForceDecode.h in Headers */, - 431BB6E31D06D2C1006A3455 /* SDImageCache.h in Headers */, - 431BB6E61D06D2C1006A3455 /* UIImageView+WebCache.h in Headers */, - 3290FA081FA478AF0047D20C /* SDImageFrame.h in Headers */, - 321E60A61F38E8F600405457 /* SDImageGIFCoder.h in Headers */, - 431BB6E71D06D2C1006A3455 /* SDWebImageCompat.h in Headers */, - 32D122342080B2EB003685A3 /* SDImageCachesManager.h in Headers */, - 32F7C0882030719600873181 /* UIImage+Transform.h in Headers */, - 431BB6E91D06D2C1006A3455 /* SDWebImageDownloaderOperation.h in Headers */, - 431BB6EB1D06D2C1006A3455 /* UIView+WebCacheOperation.h in Headers */, - 325312CC200F09910046BF1E /* SDWebImageTransition.h in Headers */, - 328BB6C52082581100760D6C /* SDDiskCache.h in Headers */, - 431BB6EE1D06D2C1006A3455 /* NSData+ImageContentType.h in Headers */, - 431BB6EF1D06D2C1006A3455 /* SDWebImagePrefetcher.h in Headers */, - 328BB6AE2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, - 32C0FDE52013426C001B8F2D /* SDWebImageIndicator.h in Headers */, - 321E60981F38E8ED00405457 /* SDImageIOCoder.h in Headers */, - 328BB6D12082581100760D6C /* SDMemoryCache.h in Headers */, - 4369C27B1D9807EC007E863A /* UIView+WebCache.h in Headers */, - 324DF4B8200A14DC008A84CC /* SDWebImageDefine.h in Headers */, - 431BB6F01D06D2C1006A3455 /* SDWebImageOperation.h in Headers */, - 32B9B53B206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, - 431BB6F61D06D2C1006A3455 /* UIImage+MultiFormat.h in Headers */, - 320CAE192086F50500CFFC80 /* SDWebImageError.h in Headers */, - 32F21B5520788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, - 807A122C1F89636300EC2A9B /* SDImageCodersManager.h in Headers */, - 431BB6F91D06D2C1006A3455 /* UIImage+GIF.h in Headers */, - 32F7C0732030114C00873181 /* SDImageTransformer.h in Headers */, - 431BB6FA1D06D2C1006A3455 /* SDWebImageDownloader.h in Headers */, - 3248476D201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, - 32D122222080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, - 32484779201775F600AF9E5A /* SDAnimatedImage.h in Headers */, - 327054D8206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, - 43A918681D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4397D2B91D0DDD8C00BB2784 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 321E60A71F38E8F600405457 /* SDImageGIFCoder.h in Headers */, - 324DF4B9200A14DC008A84CC /* SDWebImageDefine.h in Headers */, - 32F7C0892030719600873181 /* UIImage+Transform.h in Headers */, - 32D122232080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, - 32B9B53C206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, - 328BB6AF2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, - 321B37922083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, - 4397D2C01D0DDD8C00BB2784 /* SDWebImage.h in Headers */, - 32F21B5620788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, - 4397D2C31D0DDD8C00BB2784 /* SDWebImageManager.h in Headers */, - 327054D9206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, - 321E60991F38E8ED00405457 /* SDImageIOCoder.h in Headers */, - 4397D2C41D0DDD8C00BB2784 /* SDImageCache.h in Headers */, - 3248476E201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, - 4397D2C51D0DDD8C00BB2784 /* UIImageView+WebCache.h in Headers */, - 3290FA091FA478AF0047D20C /* SDImageFrame.h in Headers */, - 4369C27C1D9807EC007E863A /* UIView+WebCache.h in Headers */, - 4397D2C81D0DDD8C00BB2784 /* SDWebImageCompat.h in Headers */, - 4397D2CB1D0DDD8C00BB2784 /* UIImageView+HighlightedWebCache.h in Headers */, - 320CAE1A2086F50500CFFC80 /* SDWebImageError.h in Headers */, - 32FDE8832088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, - 4397D2D01D0DDD8C00BB2784 /* SDWebImageDownloaderOperation.h in Headers */, - 3248477A201775F600AF9E5A /* SDAnimatedImage.h in Headers */, - 329A185E1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, - 320224BB203979BA00E9F285 /* SDAnimatedImageRep.h in Headers */, - 328BB6C62082581100760D6C /* SDDiskCache.h in Headers */, - 32CF1C0C1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, - 43A918691D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, - 4397D2D81D0DDD8C00BB2784 /* UIButton+WebCache.h in Headers */, - 32F7C0742030114C00873181 /* SDImageTransformer.h in Headers */, - 328BB6D22082581100760D6C /* SDMemoryCache.h in Headers */, - 321B37862083290E00C0EA77 /* SDImageLoader.h in Headers */, - 4397D2D91D0DDD8C00BB2784 /* SDWebImagePrefetcher.h in Headers */, - 32C0FDE62013426C001B8F2D /* SDWebImageIndicator.h in Headers */, - 4397D2DA1D0DDD8C00BB2784 /* UIView+WebCacheOperation.h in Headers */, - 4397D2DB1D0DDD8C00BB2784 /* UIImage+MultiFormat.h in Headers */, - 4397D2DC1D0DDD8C00BB2784 /* SDWebImageOperation.h in Headers */, - 4397D2F61D0DE2DF00BB2784 /* NSImage+Compatibility.h in Headers */, - 4397D2E11D0DDD8C00BB2784 /* SDWebImageDownloader.h in Headers */, - 321E608B1F38E8C800405457 /* SDImageCoder.h in Headers */, - 321E60C31F38E91700405457 /* UIImage+ForceDecode.h in Headers */, - 32D122352080B2EB003685A3 /* SDImageCachesManager.h in Headers */, - 32484768201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, - 325312CD200F09910046BF1E /* SDWebImageTransition.h in Headers */, - 4397D2EA1D0DDD8C00BB2784 /* UIImage+GIF.h in Headers */, - 4397D2EB1D0DDD8C00BB2784 /* NSData+ImageContentType.h in Headers */, - 321DB3612011D4D70015D2CB /* NSButton+WebCache.h in Headers */, - 807A122D1F89636300EC2A9B /* SDImageCodersManager.h in Headers */, - 328BB6A12081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 4A2CADFC1AB4BB5300B6BC39 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -1202,6 +611,7 @@ 321E60961F38E8ED00405457 /* SDImageIOCoder.h in Headers */, 4A2CAE041AB4BB5400B6BC39 /* SDWebImage.h in Headers */, 327054D6206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, + 80B6DF842142B44600BCB334 /* NSButton+WebCache.h in Headers */, 43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 3290FA061FA478AF0047D20C /* SDImageFrame.h in Headers */, 324DF4B6200A14DC008A84CC /* SDWebImageDefine.h in Headers */, @@ -1211,7 +621,6 @@ 4A2CAE351AB4BB7500B6BC39 /* UIImageView+WebCache.h in Headers */, 320CAE172086F50500CFFC80 /* SDWebImageError.h in Headers */, 4A2CAE181AB4BB6400B6BC39 /* SDWebImageCompat.h in Headers */, - 32FDE8812088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, 4A2CAE331AB4BB7500B6BC39 /* UIImageView+HighlightedWebCache.h in Headers */, 328BB6C32082581100760D6C /* SDDiskCache.h in Headers */, 4A2CAE1D1AB4BB6800B6BC39 /* SDWebImageDownloaderOperation.h in Headers */, @@ -1222,6 +631,7 @@ 4A2CAE371AB4BB7500B6BC39 /* UIView+WebCacheOperation.h in Headers */, 321B37832083290E00C0EA77 /* SDImageLoader.h in Headers */, 32484777201775F600AF9E5A /* SDAnimatedImage.h in Headers */, + 80B6DF812142B43B00BCB334 /* SDAnimatedImageRep.h in Headers */, 4A2CAE2F1AB4BB7500B6BC39 /* UIImage+MultiFormat.h in Headers */, 325312CA200F09910046BF1E /* SDWebImageTransition.h in Headers */, 4A2CAE1A1AB4BB6400B6BC39 /* SDWebImageOperation.h in Headers */, @@ -1233,6 +643,7 @@ 32D122322080B2EB003685A3 /* SDImageCachesManager.h in Headers */, 32F7C0862030719600873181 /* UIImage+Transform.h in Headers */, 321E60C01F38E91700405457 /* UIImage+ForceDecode.h in Headers */, + 80B6DF7F2142B43300BCB334 /* NSImage+Compatibility.h in Headers */, 32C0FDE32013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 32F7C0712030114C00873181 /* SDImageTransformer.h in Headers */, 4A2CAE2D1AB4BB7500B6BC39 /* UIImage+GIF.h in Headers */, @@ -1255,6 +666,7 @@ 328BB6C12082581100760D6C /* SDDiskCache.h in Headers */, 53761318155AD0D5005750A4 /* SDWebImageCompat.h in Headers */, 3290FA041FA478AF0047D20C /* SDImageFrame.h in Headers */, + 80B6DF852142B44700BCB334 /* NSButton+WebCache.h in Headers */, 807A12281F89636300EC2A9B /* SDImageCodersManager.h in Headers */, 32B9B537206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 32484775201775F600AF9E5A /* SDAnimatedImage.h in Headers */, @@ -1267,7 +679,6 @@ 328BB6AA2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 32F21B5120788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 5376131C155AD0D5005750A4 /* SDWebImageManager.h in Headers */, - 32FDE8802088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, 321E60BE1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 5376131E155AD0D5005750A4 /* SDWebImagePrefetcher.h in Headers */, 32F7C06F2030114C00873181 /* SDImageTransformer.h in Headers */, @@ -1275,6 +686,7 @@ 32FDE8A220888789008D7530 /* SDWebImage.h in Headers */, 324DF4B4200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 5376131F155AD0D5005750A4 /* UIButton+WebCache.h in Headers */, + 80B6DF802142B43A00BCB334 /* SDAnimatedImageRep.h in Headers */, 327054D4206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, 53761320155AD0D5005750A4 /* UIImageView+WebCache.h in Headers */, 328BB69C2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, @@ -1286,6 +698,7 @@ 321B37812083290E00C0EA77 /* SDImageLoader.h in Headers */, 321E60861F38E8C800405457 /* SDImageCoder.h in Headers */, 32484763201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, + 80B6DF7E2142B43300BCB334 /* NSImage+Compatibility.h in Headers */, 32D1221E2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, AB615303192DA24600A2D8E9 /* UIView+WebCacheOperation.h in Headers */, A18A6CC7172DC28500419892 /* UIImage+GIF.h in Headers */, @@ -1294,84 +707,21 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 80B6DFB82142B71600BCB334 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 806BE07E2142C65200E02143 /* SDWebImageMapKit.h in Headers */, + 80B6DFCD2142B71600BCB334 /* MKAnnotationView+WebCache.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - 00733A4B1BC487C000A5A117 /* SDWebImage tvOS */ = { + 4A2CADFE1AB4BB5300B6BC39 /* SDWebImage */ = { isa = PBXNativeTarget; - buildConfigurationList = 00733A531BC487C100A5A117 /* Build configuration list for PBXNativeTarget "SDWebImage tvOS" */; - buildPhases = ( - 00733A471BC487C000A5A117 /* Sources */, - 00733A481BC487C000A5A117 /* Frameworks */, - 00733A491BC487C000A5A117 /* Headers */, - 00733A4A1BC487C000A5A117 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "SDWebImage tvOS"; - productName = "WebImage tvOS"; - productReference = 00733A4C1BC487C000A5A117 /* SDWebImage.framework */; - productType = "com.apple.product-type.framework"; - }; - 4314D11B1D0E0E3B004B36C9 /* SDWebImage watchOS static */ = { - isa = PBXNativeTarget; - buildConfigurationList = 4314D1961D0E0E3B004B36C9 /* Build configuration list for PBXNativeTarget "SDWebImage watchOS static" */; - buildPhases = ( - 4314D11C1D0E0E3B004B36C9 /* Sources */, - 4314D15D1D0E0E3B004B36C9 /* Frameworks */, - 4314D1611D0E0E3B004B36C9 /* Headers */, - 4314D1951D0E0E3B004B36C9 /* Prepare Framework */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "SDWebImage watchOS static"; - productName = SDWebImage; - productReference = 4314D1991D0E0E3B004B36C9 /* libSDWebImage watchOS static.a */; - productType = "com.apple.product-type.library.static"; - }; - 431BB6891D06D2C1006A3455 /* SDWebImage watchOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 431BB7001D06D2C1006A3455 /* Build configuration list for PBXNativeTarget "SDWebImage watchOS" */; - buildPhases = ( - 431BB68A1D06D2C1006A3455 /* Sources */, - 431BB6CA1D06D2C1006A3455 /* Frameworks */, - 431BB6CB1D06D2C1006A3455 /* Headers */, - 431BB6FF1D06D2C1006A3455 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "SDWebImage watchOS"; - productName = "WebImage tvOS"; - productReference = 431BB7031D06D2C1006A3455 /* SDWebImage.framework */; - productType = "com.apple.product-type.framework"; - }; - 4397D2761D0DDD8C00BB2784 /* SDWebImage OSX */ = { - isa = PBXNativeTarget; - buildConfigurationList = 4397D2EF1D0DDD8C00BB2784 /* Build configuration list for PBXNativeTarget "SDWebImage OSX" */; - buildPhases = ( - 4397D2771D0DDD8C00BB2784 /* Sources */, - 4397D2B81D0DDD8C00BB2784 /* Frameworks */, - 4397D2B91D0DDD8C00BB2784 /* Headers */, - 4397D2EE1D0DDD8C00BB2784 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "SDWebImage OSX"; - productName = WebImage; - productReference = 4397D2F21D0DDD8C00BB2784 /* SDWebImage.framework */; - productType = "com.apple.product-type.framework"; - }; - 4A2CADFE1AB4BB5300B6BC39 /* SDWebImage iOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 4A2CAE121AB4BB5400B6BC39 /* Build configuration list for PBXNativeTarget "SDWebImage iOS" */; + buildConfigurationList = 4A2CAE121AB4BB5400B6BC39 /* Build configuration list for PBXNativeTarget "SDWebImage" */; buildPhases = ( 4A2CADFA1AB4BB5300B6BC39 /* Sources */, 4A2CADFB1AB4BB5300B6BC39 /* Frameworks */, @@ -1382,14 +732,14 @@ ); dependencies = ( ); - name = "SDWebImage iOS"; + name = SDWebImage; productName = WebImage; productReference = 4A2CADFF1AB4BB5300B6BC39 /* SDWebImage.framework */; productType = "com.apple.product-type.framework"; }; - 53761307155AD0D5005750A4 /* SDWebImage iOS static */ = { + 53761307155AD0D5005750A4 /* SDWebImage static */ = { isa = PBXNativeTarget; - buildConfigurationList = 53761322155AD0D5005750A4 /* Build configuration list for PBXNativeTarget "SDWebImage iOS static" */; + buildConfigurationList = 53761322155AD0D5005750A4 /* Build configuration list for PBXNativeTarget "SDWebImage static" */; buildPhases = ( 53761308155AD0D5005750A4 /* Sources */, 53761311155AD0D5005750A4 /* Frameworks */, @@ -1400,11 +750,30 @@ ); dependencies = ( ); - name = "SDWebImage iOS static"; + name = "SDWebImage static"; productName = SDWebImage; - productReference = 53761325155AD0D5005750A4 /* libSDWebImage iOS static.a */; + productReference = 53761325155AD0D5005750A4 /* libSDWebImage static.a */; productType = "com.apple.product-type.library.static"; }; + 80B6DF862142B71600BCB334 /* SDWebImageMapKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = 80B6DFEB2142B71600BCB334 /* Build configuration list for PBXNativeTarget "SDWebImageMapKit" */; + buildPhases = ( + 80B6DF872142B71600BCB334 /* Sources */, + 80B6DFB72142B71600BCB334 /* Frameworks */, + 80B6DFB82142B71600BCB334 /* Headers */, + 80B6DFEA2142B71600BCB334 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 806BE0802142C6C400E02143 /* PBXTargetDependency */, + ); + name = SDWebImageMapKit; + productName = WebImage; + productReference = 80B6DFEE2142B71600BCB334 /* SDWebImageMapKit.framework */; + productType = "com.apple.product-type.framework"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -1414,9 +783,6 @@ LastUpgradeCheck = 0940; ORGANIZATIONNAME = Dailymotion; TargetAttributes = { - 00733A4B1BC487C000A5A117 = { - CreatedOnToolsVersion = 7.1; - }; 4A2CADFE1AB4BB5300B6BC39 = { CreatedOnToolsVersion = 6.3; }; @@ -1434,38 +800,14 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 53761307155AD0D5005750A4 /* SDWebImage iOS static */, - 4314D11B1D0E0E3B004B36C9 /* SDWebImage watchOS static */, - 4A2CADFE1AB4BB5300B6BC39 /* SDWebImage iOS */, - 00733A4B1BC487C000A5A117 /* SDWebImage tvOS */, - 431BB6891D06D2C1006A3455 /* SDWebImage watchOS */, - 4397D2761D0DDD8C00BB2784 /* SDWebImage OSX */, + 53761307155AD0D5005750A4 /* SDWebImage static */, + 4A2CADFE1AB4BB5300B6BC39 /* SDWebImage */, + 80B6DF862142B71600BCB334 /* SDWebImageMapKit */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 00733A4A1BC487C000A5A117 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 431BB6FF1D06D2C1006A3455 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4397D2EE1D0DDD8C00BB2784 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 4A2CADFD1AB4BB5300B6BC39 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1473,23 +815,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 80B6DFEA2142B71600BCB334 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 4314D1951D0E0E3B004B36C9 /* Prepare Framework */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Prepare Framework"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "set -e\n\nmkdir -p \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Versions/A/Headers\"\n\n# Link the \"Current\" version to \"A\"\n/bin/ln -sfh A \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Versions/Current\"\n/bin/ln -sfh Versions/Current/Headers \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Headers\"\n/bin/ln -sfh \"Versions/Current/${PRODUCT_NAME}\" \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/${PRODUCT_NAME}\"\n\n# The -a ensures that the headers maintain the source modification date so that we don't constantly\n# cause propagating rebuilds of files that import these headers.\n/bin/cp -a \"${TARGET_BUILD_DIR}/${PUBLIC_HEADERS_FOLDER_PATH}/\" \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Versions/A/Headers\"\n"; - }; 539F912A16316D0500160719 /* Prepare Framework */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1507,217 +842,6 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 00733A471BC487C000A5A117 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3290FA0D1FA478AF0047D20C /* SDImageFrame.m in Sources */, - 00733A561BC4880000A5A117 /* SDWebImageDownloaderOperation.m in Sources */, - 321E60C71F38E91700405457 /* UIImage+ForceDecode.m in Sources */, - 328BB6A52081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, - 00733A5A1BC4880000A5A117 /* SDWebImagePrefetcher.m in Sources */, - 320CAE1E2086F50500CFFC80 /* SDWebImageError.m in Sources */, - 32CF1C101FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, - 328BB6D62082581100760D6C /* SDMemoryCache.m in Sources */, - 32F7C0782030114C00873181 /* SDImageTransformer.m in Sources */, - 00733A5B1BC4880000A5A117 /* NSData+ImageContentType.m in Sources */, - 3237F9E920161AE000A88143 /* NSImage+Compatibility.m in Sources */, - 32C0FDEA2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, - 32F21B5A20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, - 00733A551BC4880000A5A117 /* SDWebImageDownloader.m in Sources */, - 321B37962083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, - 32F7C0812030719600873181 /* UIImage+Transform.m in Sources */, - 327054DD206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, - 325312D1200F09910046BF1E /* SDWebImageTransition.m in Sources */, - 321E609D1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, - 00733A611BC4880000A5A117 /* UIImageView+WebCache.m in Sources */, - 328BB6CA2082581100760D6C /* SDDiskCache.m in Sources */, - 32484760201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, - 32D1222D2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, - 32B9B540206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, - 3248477E201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, - 43A9186E1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, - 321E60AB1F38E8F600405457 /* SDImageGIFCoder.m in Sources */, - 321E608F1F38E8C800405457 /* SDImageCoder.m in Sources */, - 00733A581BC4880000A5A117 /* SDWebImageManager.m in Sources */, - 00733A541BC4880000A5A117 /* SDWebImageCompat.m in Sources */, - 32FDE87E2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */, - 00733A621BC4880000A5A117 /* UIView+WebCacheOperation.m in Sources */, - 321B378A2083290E00C0EA77 /* SDImageLoader.m in Sources */, - 32484772201775F600AF9E5A /* SDAnimatedImage.m in Sources */, - 807A12311F89636300EC2A9B /* SDImageCodersManager.m in Sources */, - 32D122272080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, - 00733A5C1BC4880000A5A117 /* UIButton+WebCache.m in Sources */, - 324DF4BD200A14DC008A84CC /* SDWebImageDefine.m in Sources */, - 00733A5D1BC4880000A5A117 /* UIImage+GIF.m in Sources */, - 32EB6D90206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, - 00733A571BC4880000A5A117 /* SDImageCache.m in Sources */, - 4369C2811D9807EC007E863A /* UIView+WebCache.m in Sources */, - 00733A5E1BC4880000A5A117 /* UIImage+MultiFormat.m in Sources */, - 329A18621FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, - 328BB6B32081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, - 00733A601BC4880000A5A117 /* UIImageView+HighlightedWebCache.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4314D11C1D0E0E3B004B36C9 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 4314D1231D0E0E3B004B36C9 /* SDImageCache.m in Sources */, - 329A18601FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, - 32EB6D92206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, - 321E608D1F38E8C800405457 /* SDImageCoder.m in Sources */, - 4314D1311D0E0E3B004B36C9 /* SDWebImageDownloader.m in Sources */, - 4369C27F1D9807EC007E863A /* UIView+WebCache.m in Sources */, - 32D122252080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, - 3290FA0B1FA478AF0047D20C /* SDImageFrame.m in Sources */, - 807A122F1F89636300EC2A9B /* SDImageCodersManager.m in Sources */, - 4314D1361D0E0E3B004B36C9 /* SDWebImageManager.m in Sources */, - 321E609B1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, - 4314D1371D0E0E3B004B36C9 /* SDWebImagePrefetcher.m in Sources */, - 320CAE1C2086F50500CFFC80 /* SDWebImageError.m in Sources */, - 4314D13B1D0E0E3B004B36C9 /* UIButton+WebCache.m in Sources */, - 328BB6A32081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, - 32F21B5820788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, - 321E60C51F38E91700405457 /* UIImage+ForceDecode.m in Sources */, - 328BB6C82082581100760D6C /* SDDiskCache.m in Sources */, - 325312CF200F09910046BF1E /* SDWebImageTransition.m in Sources */, - 32D1222B2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, - 321B37942083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, - 3248475E201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, - 32484770201775F600AF9E5A /* SDAnimatedImage.m in Sources */, - 3248477C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, - 32C0FDE82013426C001B8F2D /* SDWebImageIndicator.m in Sources */, - 4314D1401D0E0E3B004B36C9 /* UIImageView+WebCache.m in Sources */, - 43A9186C1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, - 3237F9EC20161AE000A88143 /* NSImage+Compatibility.m in Sources */, - 4314D1411D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.m in Sources */, - 32B9B53E206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, - 32F7C0762030114C00873181 /* SDImageTransformer.m in Sources */, - 327054DB206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, - 328BB6D42082581100760D6C /* SDMemoryCache.m in Sources */, - 324DF4BB200A14DC008A84CC /* SDWebImageDefine.m in Sources */, - 4314D14B1D0E0E3B004B36C9 /* SDWebImageCompat.m in Sources */, - 328BB6B12081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, - 4314D14D1D0E0E3B004B36C9 /* UIImage+GIF.m in Sources */, - 32CF1C0E1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, - 4314D1501D0E0E3B004B36C9 /* UIView+WebCacheOperation.m in Sources */, - 321E60A91F38E8F600405457 /* SDImageGIFCoder.m in Sources */, - 4314D1521D0E0E3B004B36C9 /* NSData+ImageContentType.m in Sources */, - 4314D1531D0E0E3B004B36C9 /* UIImage+MultiFormat.m in Sources */, - 4314D1551D0E0E3B004B36C9 /* UIImageView+HighlightedWebCache.m in Sources */, - 32F7C07F2030719600873181 /* UIImage+Transform.m in Sources */, - 321B37882083290E00C0EA77 /* SDImageLoader.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 431BB68A1D06D2C1006A3455 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 431BB68C1D06D2C1006A3455 /* SDWebImageDownloaderOperation.m in Sources */, - 431BB68E1D06D2C1006A3455 /* SDWebImagePrefetcher.m in Sources */, - 329A18631FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, - 32EB6D8F206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, - 321E60901F38E8C800405457 /* SDImageCoder.m in Sources */, - 431BB6921D06D2C1006A3455 /* NSData+ImageContentType.m in Sources */, - 431BB69A1D06D2C1006A3455 /* SDWebImageDownloader.m in Sources */, - 431BB6A31D06D2C1006A3455 /* UIImageView+WebCache.m in Sources */, - 32D122282080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, - 4369C2821D9807EC007E863A /* UIView+WebCache.m in Sources */, - 3290FA0E1FA478AF0047D20C /* SDImageFrame.m in Sources */, - 431BB6AA1D06D2C1006A3455 /* SDWebImageManager.m in Sources */, - 807A12321F89636300EC2A9B /* SDImageCodersManager.m in Sources */, - 321E609E1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, - 320CAE1F2086F50500CFFC80 /* SDWebImageError.m in Sources */, - 431BB6AC1D06D2C1006A3455 /* SDWebImageCompat.m in Sources */, - 328BB6A62081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, - 32F21B5B20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, - 321E60C81F38E91700405457 /* UIImage+ForceDecode.m in Sources */, - 328BB6CB2082581100760D6C /* SDDiskCache.m in Sources */, - 325312D2200F09910046BF1E /* SDWebImageTransition.m in Sources */, - 32D1222E2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, - 431BB6B11D06D2C1006A3455 /* UIView+WebCacheOperation.m in Sources */, - 321B37972083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, - 32484761201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, - 32484773201775F600AF9E5A /* SDAnimatedImage.m in Sources */, - 3248477F201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, - 32C0FDEB2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, - 3237F9EA20161AE000A88143 /* NSImage+Compatibility.m in Sources */, - 32B9B541206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, - 32F7C0792030114C00873181 /* SDImageTransformer.m in Sources */, - 431BB6B91D06D2C1006A3455 /* UIButton+WebCache.m in Sources */, - 43A9186F1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, - 327054DE206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, - 328BB6D72082581100760D6C /* SDMemoryCache.m in Sources */, - 324DF4BE200A14DC008A84CC /* SDWebImageDefine.m in Sources */, - 328BB6B42081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, - 431BB6BD1D06D2C1006A3455 /* UIImage+GIF.m in Sources */, - 32CF1C111FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, - 321E60AC1F38E8F600405457 /* SDImageGIFCoder.m in Sources */, - 431BB6C01D06D2C1006A3455 /* SDImageCache.m in Sources */, - 431BB6C41D06D2C1006A3455 /* UIImage+MultiFormat.m in Sources */, - 32F7C0822030719600873181 /* UIImage+Transform.m in Sources */, - 321B378B2083290E00C0EA77 /* SDImageLoader.m in Sources */, - 431BB6C71D06D2C1006A3455 /* UIImageView+HighlightedWebCache.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4397D2771D0DDD8C00BB2784 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 4397D27E1D0DDD8C00BB2784 /* UIImage+GIF.m in Sources */, - 321E60911F38E8C800405457 /* SDImageCoder.m in Sources */, - 4397D2F71D0DE2DF00BB2784 /* NSImage+Compatibility.m in Sources */, - 32FDE87F2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */, - 328BB6CC2082581100760D6C /* SDDiskCache.m in Sources */, - 320CAE202086F50500CFFC80 /* SDWebImageError.m in Sources */, - 3290FA0F1FA478AF0047D20C /* SDImageFrame.m in Sources */, - 32CF1C121FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, - 32B9B542206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, - 329A18641FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, - 324DF4BF200A14DC008A84CC /* SDWebImageDefine.m in Sources */, - 4397D28C1D0DDD8C00BB2784 /* UIImageView+WebCache.m in Sources */, - 4397D28F1D0DDD8C00BB2784 /* SDWebImageDownloaderOperation.m in Sources */, - 32484762201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, - 328BB6D82082581100760D6C /* SDMemoryCache.m in Sources */, - 328BB6B52081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, - 321E60C91F38E91700405457 /* UIImage+ForceDecode.m in Sources */, - 32D1222F2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, - 4397D2921D0DDD8C00BB2784 /* SDWebImagePrefetcher.m in Sources */, - 807A12331F89636300EC2A9B /* SDImageCodersManager.m in Sources */, - 4397D2961D0DDD8C00BB2784 /* UIImage+MultiFormat.m in Sources */, - 32F21B5C20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, - 32D122292080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, - 321B378C2083290E00C0EA77 /* SDImageLoader.m in Sources */, - 4397D29B1D0DDD8C00BB2784 /* SDWebImageDownloader.m in Sources */, - 328BB6A72081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, - 4397D29C1D0DDD8C00BB2784 /* NSData+ImageContentType.m in Sources */, - 321DB3622011D4D70015D2CB /* NSButton+WebCache.m in Sources */, - 4397D2A11D0DDD8C00BB2784 /* SDWebImageManager.m in Sources */, - 321E60AD1F38E8F600405457 /* SDImageGIFCoder.m in Sources */, - 327054DF206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, - 4397D2A61D0DDD8C00BB2784 /* SDWebImageCompat.m in Sources */, - 4397D2A81D0DDD8C00BB2784 /* UIButton+WebCache.m in Sources */, - 320224BC203979BA00E9F285 /* SDAnimatedImageRep.m in Sources */, - 321E609F1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, - 32484780201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, - 43A918701D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, - 4397D2AB1D0DDD8C00BB2784 /* UIView+WebCacheOperation.m in Sources */, - 325312D3200F09910046BF1E /* SDWebImageTransition.m in Sources */, - 4369C2831D9807EC007E863A /* UIView+WebCache.m in Sources */, - 32C0FDEC2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, - 32F7C0832030719600873181 /* UIImage+Transform.m in Sources */, - 32484774201775F600AF9E5A /* SDAnimatedImage.m in Sources */, - 4397D2AE1D0DDD8C00BB2784 /* UIImageView+HighlightedWebCache.m in Sources */, - 4397D2B01D0DDD8C00BB2784 /* SDImageCache.m in Sources */, - 321B37982083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, - 32F7C07A2030114C00873181 /* SDImageTransformer.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 4A2CADFA1AB4BB5300B6BC39 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1726,6 +850,7 @@ 321E60C61F38E91700405457 /* UIImage+ForceDecode.m in Sources */, 328BB6A42081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 4A2CAE2E1AB4BB7500B6BC39 /* UIImage+GIF.m in Sources */, + 80B6DF822142B44400BCB334 /* NSButton+WebCache.m in Sources */, 320CAE1D2086F50500CFFC80 /* SDWebImageError.m in Sources */, 32CF1C0F1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, 328BB6D52082581100760D6C /* SDMemoryCache.m in Sources */, @@ -1752,7 +877,6 @@ 4A2CAE301AB4BB7500B6BC39 /* UIImage+MultiFormat.m in Sources */, 4A2CAE1C1AB4BB6800B6BC39 /* SDWebImageDownloader.m in Sources */, 4A2CAE2A1AB4BB7500B6BC39 /* NSData+ImageContentType.m in Sources */, - 32FDE87D2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */, 4A2CAE221AB4BB7000B6BC39 /* SDWebImageManager.m in Sources */, 4A2CAE191AB4BB6400B6BC39 /* SDWebImageCompat.m in Sources */, 321B37892083290E00C0EA77 /* SDImageLoader.m in Sources */, @@ -1779,6 +903,7 @@ 321E60C41F38E91700405457 /* UIImage+ForceDecode.m in Sources */, 328BB6A22081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 53761309155AD0D5005750A4 /* SDImageCache.m in Sources */, + 80B6DF832142B44500BCB334 /* NSButton+WebCache.m in Sources */, 320CAE1B2086F50500CFFC80 /* SDWebImageError.m in Sources */, 32CF1C0D1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, 328BB6D32082581100760D6C /* SDMemoryCache.m in Sources */, @@ -1805,7 +930,6 @@ 5376130E155AD0D5005750A4 /* UIButton+WebCache.m in Sources */, 5376130F155AD0D5005750A4 /* UIImageView+WebCache.m in Sources */, 530E49EC16464C84002868E7 /* SDWebImageDownloaderOperation.m in Sources */, - 32FDE87C2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */, 53406750167780C40042B59E /* SDWebImageCompat.m in Sources */, 321B37872083290E00C0EA77 /* SDImageLoader.m in Sources */, 3248476F201775F600AF9E5A /* SDAnimatedImage.m in Sources */, @@ -1824,224 +948,37 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 80B6DF872142B71600BCB334 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 80B6DFA72142B71600BCB334 /* MKAnnotationView+WebCache.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 806BE0802142C6C400E02143 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4A2CADFE1AB4BB5300B6BC39 /* SDWebImage */; + targetProxy = 806BE07F2142C6C400E02143 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin XCBuildConfiguration section */ - 00733A511BC487C100A5A117 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = YES; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = WebImage/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.$(PRODUCT_NAME:rfc1034identifier).tvos"; - PRODUCT_NAME = SDWebImage; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 9.0; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 00733A521BC487C100A5A117 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = YES; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = WebImage/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.$(PRODUCT_NAME:rfc1034identifier).tvos"; - PRODUCT_NAME = SDWebImage; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 9.0; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 4314D1971D0E0E3B004B36C9 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - PRODUCT_NAME = "$(TARGET_NAME)"; - PUBLIC_HEADERS_FOLDER_PATH = include/SDWebImage; - SDKROOT = watchos; - TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Debug; - }; - 4314D1981D0E0E3B004B36C9 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - PRODUCT_NAME = "$(TARGET_NAME)"; - PUBLIC_HEADERS_FOLDER_PATH = include/SDWebImage; - SDKROOT = watchos; - TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Release; - }; - 431BB7011D06D2C1006A3455 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = WebImage/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.$(PRODUCT_NAME:rfc1034identifier).watchos"; - PRODUCT_NAME = SDWebImage; - SDKROOT = watchos; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - TARGETED_DEVICE_FAMILY = 4; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Debug; - }; - 431BB7021D06D2C1006A3455 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = WebImage/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.$(PRODUCT_NAME:rfc1034identifier).watchos"; - PRODUCT_NAME = SDWebImage; - SDKROOT = watchos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = 4; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Release; - }; - 4397D2F01D0DDD8C00BB2784 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - COMBINE_HIDPI_IMAGES = YES; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; - INFOPLIST_FILE = WebImage/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.$(PRODUCT_NAME:rfc1034identifier).ios"; - PRODUCT_NAME = SDWebImage; - SDKROOT = macosx; - }; - name = Debug; - }; - 4397D2F11D0DDD8C00BB2784 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - COMBINE_HIDPI_IMAGES = YES; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - INFOPLIST_FILE = WebImage/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.$(PRODUCT_NAME:rfc1034identifier).ios"; - PRODUCT_NAME = SDWebImage; - SDKROOT = macosx; - }; - name = Release; - }; 4A2CAE131AB4BB5400B6BC39 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; INFOPLIST_FILE = WebImage/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.$(PRODUCT_NAME:rfc1034identifier).ios"; - PRODUCT_NAME = SDWebImage; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; + PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.$(PRODUCT_NAME:rfc1034identifier)"; }; name = Debug; }; @@ -2049,50 +986,27 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; INFOPLIST_FILE = WebImage/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.$(PRODUCT_NAME:rfc1034identifier).ios"; - PRODUCT_NAME = SDWebImage; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; + PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.$(PRODUCT_NAME:rfc1034identifier)"; }; name = Release; }; 53761323155AD0D5005750A4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - PRODUCT_NAME = "$(TARGET_NAME)"; - PUBLIC_HEADERS_FOLDER_PATH = include/SDWebImage; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 53761324155AD0D5005750A4 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - PRODUCT_NAME = "$(TARGET_NAME)"; - PUBLIC_HEADERS_FOLDER_PATH = include/SDWebImage; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; @@ -2101,6 +1015,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -2122,9 +1037,9 @@ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = NO; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -2134,15 +1049,12 @@ "\"$(SRCROOT)\"", ); GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; @@ -2155,12 +1067,19 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; - GCC_WARN_UNUSED_PARAMETER = NO; GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.10; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; RUN_CLANG_STATIC_ANALYZER = YES; + SDKROOT = macosx; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator watchsimulator watchos appletvsimulator appletvos"; + TARGETED_DEVICE_FAMILY = "1,2,3,4"; + TVOS_DEPLOYMENT_TARGET = 9.0; + WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Debug; }; @@ -2169,6 +1088,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -2190,9 +1110,9 @@ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = NO; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; CURRENT_PROJECT_VERSION = 1; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -2202,7 +1122,6 @@ ); GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; @@ -2215,55 +1134,63 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; - GCC_WARN_UNUSED_PARAMETER = NO; GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.10; OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; RUN_CLANG_STATIC_ANALYZER = YES; + SDKROOT = macosx; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator watchsimulator watchos appletvsimulator appletvos"; + TARGETED_DEVICE_FAMILY = "1,2,3,4"; + TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; + 80B6DFEC2142B71600BCB334 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = WebImage/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.$(PRODUCT_NAME:rfc1034identifier)"; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvsimulator appletvos"; + TARGETED_DEVICE_FAMILY = "1,2,3"; + TVOS_DEPLOYMENT_TARGET = 9.2; + }; + name = Debug; + }; + 80B6DFED2142B71600BCB334 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = NO; + INFOPLIST_FILE = WebImage/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.$(PRODUCT_NAME:rfc1034identifier)"; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvsimulator appletvos"; + TARGETED_DEVICE_FAMILY = "1,2,3"; + TVOS_DEPLOYMENT_TARGET = 9.2; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 00733A531BC487C100A5A117 /* Build configuration list for PBXNativeTarget "SDWebImage tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 00733A511BC487C100A5A117 /* Debug */, - 00733A521BC487C100A5A117 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 4314D1961D0E0E3B004B36C9 /* Build configuration list for PBXNativeTarget "SDWebImage watchOS static" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 4314D1971D0E0E3B004B36C9 /* Debug */, - 4314D1981D0E0E3B004B36C9 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 431BB7001D06D2C1006A3455 /* Build configuration list for PBXNativeTarget "SDWebImage watchOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 431BB7011D06D2C1006A3455 /* Debug */, - 431BB7021D06D2C1006A3455 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 4397D2EF1D0DDD8C00BB2784 /* Build configuration list for PBXNativeTarget "SDWebImage OSX" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 4397D2F01D0DDD8C00BB2784 /* Debug */, - 4397D2F11D0DDD8C00BB2784 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 4A2CAE121AB4BB5400B6BC39 /* Build configuration list for PBXNativeTarget "SDWebImage iOS" */ = { + 4A2CAE121AB4BB5400B6BC39 /* Build configuration list for PBXNativeTarget "SDWebImage" */ = { isa = XCConfigurationList; buildConfigurations = ( 4A2CAE131AB4BB5400B6BC39 /* Debug */, @@ -2272,7 +1199,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 53761322155AD0D5005750A4 /* Build configuration list for PBXNativeTarget "SDWebImage iOS static" */ = { + 53761322155AD0D5005750A4 /* Build configuration list for PBXNativeTarget "SDWebImage static" */ = { isa = XCConfigurationList; buildConfigurations = ( 53761323155AD0D5005750A4 /* Debug */, @@ -2290,6 +1217,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 80B6DFEB2142B71600BCB334 /* Build configuration list for PBXNativeTarget "SDWebImageMapKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 80B6DFEC2142B71600BCB334 /* Debug */, + 80B6DFED2142B71600BCB334 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 53922D66148C55810056699D /* Project object */; diff --git a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS static.xcscheme b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage static.xcscheme similarity index 91% rename from SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS static.xcscheme rename to SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage static.xcscheme index 4f7b486b..61e50690 100644 --- a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS static.xcscheme +++ b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage static.xcscheme @@ -15,8 +15,8 @@ @@ -46,8 +46,8 @@ diff --git a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage tvOS.xcscheme b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage tvOS.xcscheme deleted file mode 100644 index 051eaaec..00000000 --- a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage tvOS.xcscheme +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS static.xcscheme b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS static.xcscheme deleted file mode 100644 index 4f74b360..00000000 --- a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS static.xcscheme +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS.xcscheme b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS.xcscheme deleted file mode 100644 index 3759187f..00000000 --- a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage watchOS.xcscheme +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS.xcscheme b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage.xcscheme similarity index 95% rename from SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS.xcscheme rename to SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage.xcscheme index 6ce59516..c5e94640 100644 --- a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage iOS.xcscheme +++ b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage.xcscheme @@ -16,7 +16,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "4A2CADFE1AB4BB5300B6BC39" BuildableName = "SDWebImage.framework" - BlueprintName = "SDWebImage iOS" + BlueprintName = "SDWebImage" ReferencedContainer = "container:SDWebImage.xcodeproj"> @@ -47,7 +47,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "4A2CADFE1AB4BB5300B6BC39" BuildableName = "SDWebImage.framework" - BlueprintName = "SDWebImage iOS" + BlueprintName = "SDWebImage" ReferencedContainer = "container:SDWebImage.xcodeproj"> @@ -65,7 +65,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "4A2CADFE1AB4BB5300B6BC39" BuildableName = "SDWebImage.framework" - BlueprintName = "SDWebImage iOS" + BlueprintName = "SDWebImage" ReferencedContainer = "container:SDWebImage.xcodeproj"> diff --git a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX.xcscheme b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImageMapKit.xcscheme similarity index 82% rename from SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX.xcscheme rename to SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImageMapKit.xcscheme index 88623ffd..3d20ec69 100644 --- a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX.xcscheme +++ b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImageMapKit.xcscheme @@ -14,9 +14,9 @@ buildForAnalyzing = "YES"> @@ -45,9 +45,9 @@ @@ -63,9 +63,9 @@ diff --git a/WebImage/SDWebImageMapKit.h b/WebImage/SDWebImageMapKit.h new file mode 100644 index 00000000..99c14cd9 --- /dev/null +++ b/WebImage/SDWebImageMapKit.h @@ -0,0 +1,21 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Florent Vilmart + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import + +//! Project version number for WebImage. +FOUNDATION_EXPORT double WebImageMapKitVersionNumber; + +//! Project version string for WebImage. +FOUNDATION_EXPORT const unsigned char WebImageMapKitVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + +// MapKit +#import From 1ec61ad567046aa9a96fb08a1cecae92d5f5c46b Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 17 Sep 2018 17:11:15 +0800 Subject: [PATCH 273/361] Renaming the `LOCK`, `UNLOCK` with SD prefix to avoid overriding user-defined macro. Remove `LOCKBLOCK` with paired macro instead to make it easy to debug --- SDWebImage/SDAnimatedImage.m | 18 +++--- SDWebImage/SDAnimatedImageView.m | 70 +++++++++++----------- SDWebImage/SDImageCodersManager.m | 24 ++++---- SDWebImage/SDImageLoadersManager.m | 16 ++--- SDWebImage/SDMemoryCache.m | 16 ++--- SDWebImage/SDWebImageCompat.h | 14 ++--- SDWebImage/SDWebImageDownloader.m | 14 ++--- SDWebImage/SDWebImageDownloaderOperation.m | 16 ++--- SDWebImage/SDWebImageManager.m | 28 ++++----- 9 files changed, 105 insertions(+), 111 deletions(-) diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index 2ad9b72e..d2df36d0 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -104,9 +104,9 @@ static NSArray *SDBundlePreferredScales() { } - (void)didReceiveMemoryWarning:(NSNotification *)notification { - LOCKBLOCK({ - [self.imageTable removeAllObjects]; - }); + SD_LOCK(_lock); + [self.imageTable removeAllObjects]; + SD_UNLOCK(_lock); } - (NSString *)getPathForName:(NSString *)name bundle:(NSBundle *)bundle preferredScale:(CGFloat *)scale { @@ -174,18 +174,18 @@ static NSArray *SDBundlePreferredScales() { - (UIImage *)imageForName:(NSString *)name { NSParameterAssert(name); UIImage *image; - LOCKBLOCK({ - image = [self.imageTable objectForKey:name]; - }); + SD_LOCK(_lock); + image = [self.imageTable objectForKey:name]; + SD_UNLOCK(_lock); return image; } - (void)storeImage:(UIImage *)image forName:(NSString *)name { NSParameterAssert(image); NSParameterAssert(name); - LOCKBLOCK({ - [self.imageTable setObject:image forKey:name]; - }); + SD_LOCK(_lock); + [self.imageTable setObject:image forKey:name]; + SD_UNLOCK(_lock); } @end diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index b858aef6..7810744f 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -238,10 +238,10 @@ static NSUInteger SDDeviceFreeMemory() { self.animatedImageScale = 1; [_fetchQueue cancelAllOperations]; _fetchQueue = nil; - LOCKBLOCK({ - [_frameBuffer removeAllObjects]; - _frameBuffer = nil; - }); + SD_LOCK(self.lock); + [_frameBuffer removeAllObjects]; + _frameBuffer = nil; + SD_UNLOCK(self.lock); } - (void)resetProgressiveImage @@ -299,9 +299,9 @@ static NSUInteger SDDeviceFreeMemory() { self.animatedImageScale = image.scale; if (!self.isProgressive) { self.currentFrame = image; - LOCKBLOCK({ - self.frameBuffer[@(self.currentFrameIndex)] = self.currentFrame; - }); + SD_LOCK(self.lock); + self.frameBuffer[@(self.currentFrameIndex)] = self.currentFrame; + SD_UNLOCK(self.lock); } // Ensure disabled highlighting; it's not supported (see `-setHighlighted:`). @@ -420,15 +420,15 @@ static NSUInteger SDDeviceFreeMemory() { [_fetchQueue cancelAllOperations]; [_fetchQueue addOperationWithBlock:^{ NSNumber *currentFrameIndex = @(self.currentFrameIndex); - LOCKBLOCK({ - NSArray *keys = self.frameBuffer.allKeys; - // only keep the next frame for later rendering - for (NSNumber * key in keys) { - if (![key isEqualToNumber:currentFrameIndex]) { - [self.frameBuffer removeObjectForKey:key]; - } + SD_LOCK(self.lock); + NSArray *keys = self.frameBuffer.allKeys; + // only keep the next frame for later rendering + for (NSNumber * key in keys) { + if (![key isEqualToNumber:currentFrameIndex]) { + [self.frameBuffer removeObjectForKey:key]; } - }); + } + SD_UNLOCK(self.lock); }]; } @@ -690,22 +690,22 @@ static NSUInteger SDDeviceFreeMemory() { // Update the current frame UIImage *currentFrame; UIImage *fetchFrame; - LOCKBLOCK({ - currentFrame = self.frameBuffer[@(currentFrameIndex)]; - fetchFrame = currentFrame ? self.frameBuffer[@(nextFrameIndex)] : nil; - }); + SD_LOCK(self.lock); + currentFrame = self.frameBuffer[@(currentFrameIndex)]; + fetchFrame = currentFrame ? self.frameBuffer[@(nextFrameIndex)] : nil; + SD_UNLOCK(self.lock); BOOL bufferFull = NO; if (currentFrame) { - LOCKBLOCK({ - // Remove the frame buffer if need - if (self.frameBuffer.count > self.maxBufferCount) { - self.frameBuffer[@(currentFrameIndex)] = nil; - } - // Check whether we can stop fetch - if (self.frameBuffer.count == totalFrameCount) { - bufferFull = YES; - } - }); + SD_LOCK(self.lock); + // Remove the frame buffer if need + if (self.frameBuffer.count > self.maxBufferCount) { + self.frameBuffer[@(currentFrameIndex)] = nil; + } + // Check whether we can stop fetch + if (self.frameBuffer.count == totalFrameCount) { + bufferFull = YES; + } + SD_UNLOCK(self.lock); self.currentFrame = currentFrame; self.currentFrameIndex = nextFrameIndex; self.bufferMiss = NO; @@ -720,9 +720,9 @@ static NSUInteger SDDeviceFreeMemory() { if (self.isProgressive) { // Recovery the current frame index and removed frame buffer (See above) self.currentFrameIndex = currentFrameIndex; - LOCKBLOCK({ - self.frameBuffer[@(currentFrameIndex)] = self.currentFrame; - }); + SD_LOCK(self.lock); + self.frameBuffer[@(currentFrameIndex)] = self.currentFrame; + SD_UNLOCK(self.lock); [self stopAnimating]; return; } @@ -751,9 +751,9 @@ static NSUInteger SDDeviceFreeMemory() { UIImage *animatedImage = self.animatedImage; NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ UIImage *frame = [animatedImage animatedImageFrameAtIndex:fetchFrameIndex]; - LOCKBLOCK({ - self.frameBuffer[@(fetchFrameIndex)] = frame; - }); + SD_LOCK(self.lock); + self.frameBuffer[@(fetchFrameIndex)] = frame; + SD_UNLOCK(self.lock); }]; [self.fetchQueue addOperation:operation]; } diff --git a/SDWebImage/SDImageCodersManager.m b/SDWebImage/SDImageCodersManager.m index b15ae921..7572049f 100644 --- a/SDWebImage/SDImageCodersManager.m +++ b/SDWebImage/SDImageCodersManager.m @@ -44,32 +44,32 @@ if (![coder conformsToProtocol:@protocol(SDImageCoder)]) { return; } - LOCK(self.codersLock); + SD_LOCK(self.codersLock); NSMutableArray> *mutableCoders = [self.coders mutableCopy]; if (!mutableCoders) { mutableCoders = [NSMutableArray array]; } [mutableCoders addObject:coder]; self.coders = [mutableCoders copy]; - UNLOCK(self.codersLock); + SD_UNLOCK(self.codersLock); } - (void)removeCoder:(nonnull id)coder { if (![coder conformsToProtocol:@protocol(SDImageCoder)]) { return; } - LOCK(self.codersLock); + SD_LOCK(self.codersLock); NSMutableArray> *mutableCoders = [self.coders mutableCopy]; [mutableCoders removeObject:coder]; self.coders = [mutableCoders copy]; - UNLOCK(self.codersLock); + SD_UNLOCK(self.codersLock); } #pragma mark - SDImageCoder - (BOOL)canDecodeFromData:(NSData *)data { - LOCK(self.codersLock); + SD_LOCK(self.codersLock); NSArray> *coders = self.coders; - UNLOCK(self.codersLock); + SD_UNLOCK(self.codersLock); for (id coder in coders.reverseObjectEnumerator) { if ([coder canDecodeFromData:data]) { return YES; @@ -79,9 +79,9 @@ } - (BOOL)canEncodeToFormat:(SDImageFormat)format { - LOCK(self.codersLock); + SD_LOCK(self.codersLock); NSArray> *coders = self.coders; - UNLOCK(self.codersLock); + SD_UNLOCK(self.codersLock); for (id coder in coders.reverseObjectEnumerator) { if ([coder canEncodeToFormat:format]) { return YES; @@ -95,9 +95,9 @@ return nil; } UIImage *image; - LOCK(self.codersLock); + SD_LOCK(self.codersLock); NSArray> *coders = self.coders; - UNLOCK(self.codersLock); + SD_UNLOCK(self.codersLock); for (id coder in coders.reverseObjectEnumerator) { if ([coder canDecodeFromData:data]) { image = [coder decodedImageWithData:data options:options]; @@ -112,9 +112,9 @@ if (!image) { return nil; } - LOCK(self.codersLock); + SD_LOCK(self.codersLock); NSArray> *coders = self.coders; - UNLOCK(self.codersLock); + SD_UNLOCK(self.codersLock); for (id coder in coders.reverseObjectEnumerator) { if ([coder canEncodeToFormat:format]) { return [coder encodedDataWithImage:image format:format options:nil]; diff --git a/SDWebImage/SDImageLoadersManager.m b/SDWebImage/SDImageLoadersManager.m index 0e0a0c5d..84461fce 100644 --- a/SDWebImage/SDImageLoadersManager.m +++ b/SDWebImage/SDImageLoadersManager.m @@ -42,33 +42,33 @@ if (![loader conformsToProtocol:@protocol(SDImageLoader)]) { return; } - LOCK(self.loadersLock); + SD_LOCK(self.loadersLock); NSMutableArray> *mutableLoaders = [self.loaders mutableCopy]; if (!mutableLoaders) { mutableLoaders = [NSMutableArray array]; } [mutableLoaders addObject:loader]; self.loaders = [mutableLoaders copy]; - UNLOCK(self.loadersLock); + SD_UNLOCK(self.loadersLock); } - (void)removeLoader:(id)loader { if (![loader conformsToProtocol:@protocol(SDImageLoader)]) { return; } - LOCK(self.loadersLock); + SD_LOCK(self.loadersLock); NSMutableArray> *mutableLoaders = [self.loaders mutableCopy]; [mutableLoaders removeObject:loader]; self.loaders = [mutableLoaders copy]; - UNLOCK(self.loadersLock); + SD_UNLOCK(self.loadersLock); } #pragma mark - SDImageLoader - (BOOL)canLoadWithURL:(nullable NSURL *)url { - LOCK(self.loadersLock); + SD_LOCK(self.loadersLock); NSArray> *loaders = self.loaders; - UNLOCK(self.loadersLock); + SD_UNLOCK(self.loadersLock); for (id loader in loaders.reverseObjectEnumerator) { if ([loader canLoadWithURL:url]) { return YES; @@ -81,9 +81,9 @@ if (!url) { return nil; } - LOCK(self.loadersLock); + SD_LOCK(self.loadersLock); NSArray> *loaders = self.loaders; - UNLOCK(self.loadersLock); + SD_UNLOCK(self.loadersLock); for (id loader in loaders.reverseObjectEnumerator) { if ([loader canLoadWithURL:url]) { return [loader loadImageWithURL:url options:options context:context progress:progressBlock completed:completedBlock]; diff --git a/SDWebImage/SDMemoryCache.m b/SDWebImage/SDMemoryCache.m index 45759650..d99ac764 100644 --- a/SDWebImage/SDMemoryCache.m +++ b/SDWebImage/SDMemoryCache.m @@ -89,9 +89,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext; } if (key && obj) { // Store weak cache - LOCK(self.weakCacheLock); + SD_LOCK(self.weakCacheLock); [self.weakCache setObject:obj forKey:key]; - UNLOCK(self.weakCacheLock); + SD_UNLOCK(self.weakCacheLock); } } @@ -102,9 +102,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext; } if (key && !obj) { // Check weak cache - LOCK(self.weakCacheLock); + SD_LOCK(self.weakCacheLock); obj = [self.weakCache objectForKey:key]; - UNLOCK(self.weakCacheLock); + SD_UNLOCK(self.weakCacheLock); if (obj) { // Sync cache NSUInteger cost = 0; @@ -124,9 +124,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext; } if (key) { // Remove weak cache - LOCK(self.weakCacheLock); + SD_LOCK(self.weakCacheLock); [self.weakCache removeObjectForKey:key]; - UNLOCK(self.weakCacheLock); + SD_UNLOCK(self.weakCacheLock); } } @@ -136,9 +136,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext; return; } // Manually remove should also remove weak cache - LOCK(self.weakCacheLock); + SD_LOCK(self.weakCacheLock); [self.weakCache removeAllObjects]; - UNLOCK(self.weakCacheLock); + SD_UNLOCK(self.weakCacheLock); } #endif diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index c58cbdab..92bcf4ba 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -94,16 +94,10 @@ } #endif -#ifndef LOCK -#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); +#ifndef SD_LOCK +#define SD_LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); #endif -#ifndef UNLOCK -#define UNLOCK(lock) dispatch_semaphore_signal(lock); -#endif - -#ifndef LOCKBLOCK -#define LOCKBLOCK(...) dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER); \ -__VA_ARGS__; \ -dispatch_semaphore_signal(self->_lock); +#ifndef SD_UNLOCK +#define SD_UNLOCK(lock) dispatch_semaphore_signal(lock); #endif diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 55323361..2b9edebf 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -184,13 +184,13 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; return nil; } - LOCK(self.operationsLock); + SD_LOCK(self.operationsLock); NSOperation *operation = [self.URLOperations objectForKey:url]; if (!operation || operation.isFinished) { // There is a case that the operation may be marked as finished, but not been removed from `self.URLOperations`. operation = [self createDownloaderOperationWithUrl:url options:options context:context]; if (!operation) { - UNLOCK(self.operationsLock); + SD_UNLOCK(self.operationsLock); if (completedBlock) { NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidDownloadOperation userInfo:@{NSLocalizedDescriptionKey : @"Downloader operation is nil"}]; completedBlock(nil, nil, error, YES); @@ -203,16 +203,16 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; if (!sself) { return; } - LOCK(sself.operationsLock); + SD_LOCK(sself.operationsLock); [sself.URLOperations removeObjectForKey:url]; - UNLOCK(sself.operationsLock); + SD_UNLOCK(sself.operationsLock); }; self.URLOperations[url] = operation; // Add operation to operation queue only after all configuration done according to Apple's doc. // `addOperation:` does not synchronously execute the `operation.completionBlock` so this will not cause deadlock. [self.downloadQueue addOperation:operation]; } - UNLOCK(self.operationsLock); + SD_UNLOCK(self.operationsLock); id downloadOperationCancelToken = [operation addHandlersForProgress:progressBlock completed:completedBlock]; @@ -300,7 +300,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; if (!url) { return; } - LOCK(self.operationsLock); + SD_LOCK(self.operationsLock); NSOperation *operation = [self.URLOperations objectForKey:url]; if (operation) { BOOL canceled = [operation cancel:token.downloadOperationCancelToken]; @@ -308,7 +308,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; [self.URLOperations removeObjectForKey:url]; } } - UNLOCK(self.operationsLock); + SD_UNLOCK(self.operationsLock); } - (void)cancelAllDownloads { diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 2a40af00..427d939e 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -97,16 +97,16 @@ typedef NSMutableDictionary SDCallbacksDictionary; SDCallbacksDictionary *callbacks = [NSMutableDictionary new]; if (progressBlock) callbacks[kProgressCallbackKey] = [progressBlock copy]; if (completedBlock) callbacks[kCompletedCallbackKey] = [completedBlock copy]; - LOCK(self.callbacksLock); + SD_LOCK(self.callbacksLock); [self.callbackBlocks addObject:callbacks]; - UNLOCK(self.callbacksLock); + SD_UNLOCK(self.callbacksLock); return callbacks; } - (nullable NSArray *)callbacksForKey:(NSString *)key { - LOCK(self.callbacksLock); + SD_LOCK(self.callbacksLock); NSMutableArray *callbacks = [[self.callbackBlocks valueForKey:key] mutableCopy]; - UNLOCK(self.callbacksLock); + SD_UNLOCK(self.callbacksLock); // We need to remove [NSNull null] because there might not always be a progress block for each callback [callbacks removeObjectIdenticalTo:[NSNull null]]; return [callbacks copy]; // strip mutability here @@ -114,12 +114,12 @@ typedef NSMutableDictionary SDCallbacksDictionary; - (BOOL)cancel:(nullable id)token { BOOL shouldCancel = NO; - LOCK(self.callbacksLock); + SD_LOCK(self.callbacksLock); [self.callbackBlocks removeObjectIdenticalTo:token]; if (self.callbackBlocks.count == 0) { shouldCancel = YES; } - UNLOCK(self.callbacksLock); + SD_UNLOCK(self.callbacksLock); if (shouldCancel) { [self cancel]; } @@ -259,9 +259,9 @@ typedef NSMutableDictionary SDCallbacksDictionary; } - (void)reset { - LOCK(self.callbacksLock); + SD_LOCK(self.callbacksLock); [self.callbackBlocks removeAllObjects]; - UNLOCK(self.callbacksLock); + SD_UNLOCK(self.callbacksLock); self.dataTask = nil; if (self.ownedSession) { diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 4f40307a..a18b0a24 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -136,9 +136,9 @@ static id _defaultImageLoader; BOOL isFailedUrl = NO; if (url) { - LOCK(self.failedURLsLock); + SD_LOCK(self.failedURLsLock); isFailedUrl = [self.failedURLs containsObject:url]; - UNLOCK(self.failedURLsLock); + SD_UNLOCK(self.failedURLsLock); } if (url.absoluteString.length == 0 || (!(options & SDWebImageRetryFailed) && isFailedUrl)) { @@ -146,9 +146,9 @@ static id _defaultImageLoader; return operation; } - LOCK(self.runningOperationsLock); + SD_LOCK(self.runningOperationsLock); [self.runningOperations addObject:operation]; - UNLOCK(self.runningOperationsLock); + SD_UNLOCK(self.runningOperationsLock); // Preprocess the context arg to provide the default value from manager context = [self processedContextWithContext:context]; @@ -160,17 +160,17 @@ static id _defaultImageLoader; } - (void)cancelAll { - LOCK(self.runningOperationsLock); + SD_LOCK(self.runningOperationsLock); NSSet *copiedOperations = [self.runningOperations copy]; - UNLOCK(self.runningOperationsLock); + SD_UNLOCK(self.runningOperationsLock); [copiedOperations makeObjectsPerformSelector:@selector(cancel)]; // This will call `safelyRemoveOperationFromRunning:` and remove from the array } - (BOOL)isRunning { BOOL isRunning = NO; - LOCK(self.runningOperationsLock); + SD_LOCK(self.runningOperationsLock); isRunning = (self.runningOperations.count > 0); - UNLOCK(self.runningOperationsLock); + SD_UNLOCK(self.runningOperationsLock); return isRunning; } @@ -261,15 +261,15 @@ static id _defaultImageLoader; } if (shouldBlockFailedURL) { - LOCK(self.failedURLsLock); + SD_LOCK(self.failedURLsLock); [self.failedURLs addObject:url]; - UNLOCK(self.failedURLsLock); + SD_UNLOCK(self.failedURLsLock); } } else { if ((options & SDWebImageRetryFailed)) { - LOCK(self.failedURLsLock); + SD_LOCK(self.failedURLsLock); [self.failedURLs removeObject:url]; - UNLOCK(self.failedURLsLock); + SD_UNLOCK(self.failedURLsLock); } SDImageCacheType storeCacheType = SDImageCacheTypeAll; @@ -338,9 +338,9 @@ static id _defaultImageLoader; if (!operation) { return; } - LOCK(self.runningOperationsLock); + SD_LOCK(self.runningOperationsLock); [self.runningOperations removeObject:operation]; - UNLOCK(self.runningOperationsLock); + SD_UNLOCK(self.runningOperationsLock); } - (void)callCompletionBlockForOperation:(nullable SDWebImageCombinedOperation*)operation From 3a8915c5c70c77e9ae5c20a34b4619c1f376a810 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Jul 2018 16:44:59 +0800 Subject: [PATCH 274/361] Update the migration guide with the latest version. Update one changelog --- CHANGELOG.md | 2 +- Docs/SDWebImage-5.0-Migration-guide.md | 55 +++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1763d3ce..0dab3171 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,7 +80,7 @@ See the [5.0 Migration Guide](https://raw.githubusercontent.com/rs/SDWebImage/5. - `SDImageCache` now uses `NSData writeToFile:options:error` instead of `NSFileManager createFileAtPath:contents:attributes` #2148 - Moved `SDImageCache maxMemoryCost` and `SDImageCache maxMemoryCountLimit` to `SDImageCacheConfig` #2151 - Added `SDImageCache diskImageDataExistsWithKey:` synchronous method #2151 -- Moved `UIImage sd_imageLoopCount` and `UIImage isGIF` (and renamed to `sd_isAnimated`) to `UIImage+WebCache` category, removed the outdated methods #2152 +- Moved `UIImage sd_imageLoopCount` and `UIImage isGIF` (and renamed to `sd_isAnimated`) to `UIImage+Metadata` category, removed the outdated methods #2152 - Move context and other type definitions to a separate header (`SDWebImageDefine`) to allow to be included without dependency #2188 - Pass `context` arg from the top level APIs to the bottom level APIs to allow specify logic in the future #2189 d6a3e2c c24c3d3 - Refactor the image indicator by creating `SDWebImageIndicator` and `SDWebImageProgressIndicator` protocols and two concrete classes that implement activity and progress indicators for both UIKit and AppKit #2185 46b62cf diff --git a/Docs/SDWebImage-5.0-Migration-guide.md b/Docs/SDWebImage-5.0-Migration-guide.md index 4ef9cf4c..e684823e 100644 --- a/Docs/SDWebImage-5.0-Migration-guide.md +++ b/Docs/SDWebImage-5.0-Migration-guide.md @@ -38,9 +38,9 @@ In 5.0, we introduced a brand new mechanism for supporting animated images. This This animated image solution is available for `iOS`/`tvOS`/`macOS`. The `SDAnimatedImage` is subclass of `UIImage/NSImage`, and `SDAnimatedImageView` is subclass of `UIImageView/NSImageView`, to make them compatible with the common frameworks APIs. See [Animated Image](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#animated-image-50) for more detailed information. -#### Transformer +#### Image Transformer -In 5.0, we introduced an easy way to hook an image transformation process after the image was downloaded from network. This allows the user to easily scale, rotate, add rounded corner the original image and even chain a list of transformations. These transformed images will also be stored to the cache as they are after transformation. The reasons for this decision are: avoiding redoing the transformations (which can lead to unwanted behavior) and also time saving. See [Image Transformer](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#transformer-50) for more detailed information. +In 5.0, we introduced an easy way to hook an image transformation process after the image was downloaded from network. This allows the user to easily scale, rotate, add rounded corner the original image and even chain a list of transformations. These transformed images will also be stored to the cache as they are after transformation. The reasons for this decision are: avoiding redoing the transformations (which can lead to unwanted behavior) and also time saving. See [Image Transformer](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#image-transformer-50) for more detailed information. #### Customization @@ -58,6 +58,51 @@ In order to clean up things and make our core project do less things, we decided By taking the advantage of the [Custom Loader](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-loader-50) feature, we introduced a plugin to allow easy loading images from the Photos Library. See [SDWebImagePhotosPlugin](https://github.com/SDWebImage/SDWebImagePhotosPlugin) for more detailed information. +### Notable Behavior Changes + +#### Cache + +`SDImageCache` in 5.x, use `~/Library/com.hackemist.SDImageCache.default` as default cache path. However, 4.x use `~/Library/com.hackemist.SDWebImageCache.default`. If you have images in cache, it may be lost during migration. + +If you still want to keep the 4.x default cache path, you can custom the cache path prefix using `namespacePrefix` property. + ++ Objective-C + +```objective-c +SDImageCacheConfig.defaultCacheConfig.namespacePrefix = @"com.hackemist.SDWebImageCache."; +``` + ++ Swift + +```swift +SDImageCacheConfig.`default`.namespacePrefix = "com.hackemist.SDWebImageCache." +``` + +#### Prefetcher + +`SDWebImagePrefetcher` in 5.x, change the concept of fetching batch of URLs. Now, each time you call `prefetchURLs:`, you will get a token which represents the specified URLs list. It does not cancel the previous URLs which is prefetching, which make the shared prefetcher behaves more intuitively. + +However, in 4.x, each time you call `prefetchURLs:`, it will cancel all previous URLs which is been prefetching. + +If you still want the same behavior, manually call `cancelPrefetching` each time before any `prefetchURLs:` calls. + + ++ Objective-C + +```objective-c +SDWebImagePrefetcher *prefetcher = SDWebImagePrefetcher.sharedImagePrefetcher; +[prefetcher cancelPrefetching]; +[prefetcher prefetchURLs:@[url1, url2]]; +``` + ++ Swift + +```swift +let prefetcher = SDWebImagePrefetcher.shared +prefetcher.cancelPrefetching() +prefetcher.prefetchURLs([url1, url2]) +``` + ### API Changes #### SDImageCache @@ -132,8 +177,8 @@ By taking the advantage of the [Custom Loader](https://github.com/rs/SDWebImage/ - `headersFilter` removed, use `requestModifier` instead - `cancel:` removed, use `-[SDWebImageDownloadToken cancel]` instead - `shouldDecompressImages` removed. Use `SDWebImageDownloaderAvoidDecodeImage` in downloader options instead -- use `SDWebImageLoaderProgressBlock` instead of `SDWebImageDownloaderProgressBlock` -- use `SDWebImageLoaderCompletedBlock` instead of `SDWebImageDownloaderCompletedBlock` +- use `SDImageLoaderProgressBlock` instead of `SDWebImageDownloaderProgressBlock` +- use `SDImageLoaderCompletedBlock` instead of `SDWebImageDownloaderCompletedBlock` #### SDWebImageDownloaderOperation @@ -215,5 +260,5 @@ In SDWebImage 5.0 we did a clean up of the API. We are using many modern Objecti - `sd_currentAlternateImageURL()` changed to `sd_currentAlternateImageURL` ### Full API Diff -For advanced user who need the detailed API diff, we provide the full diff in a HTML web page: [SDWebImage 5.0 API Diff](https://raw.githubusercontent.com/rs/SDWebImage/5.x/Docs/API-Diff/5.0/apidiff.html) +For advanced user who need the detailed API diff, we provide the full diff in a HTML web page: [SDWebImage 5.0 API Diff](https://htmlpreview.github.io/?https://github.com/rs/SDWebImage/blob/5.x/Docs/API-Diff/5.0/apidiff.html) From 3131c092847843d7b25dbfd71490966e8bb2e831 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 24 Sep 2018 19:32:09 +0800 Subject: [PATCH 275/361] Update the API-diff to the latest 5.x branch --- Docs/API-Diff/5.0/apidiff.html | 156 ++++++++++++++++++++++++++++----- 1 file changed, 132 insertions(+), 24 deletions(-) diff --git a/Docs/API-Diff/5.0/apidiff.html b/Docs/API-Diff/5.0/apidiff.html index 02d5349f..13c7d66c 100644 --- a/Docs/API-Diff/5.0/apidiff.html +++ b/Docs/API-Diff/5.0/apidiff.html @@ -5,17 +5,71 @@ +
+
FLAnimatedImage.h
+ +
+
Removed kFLAnimatedImageDelayTimeIntervalMinimum
+
Removed FLAnimatedImage
+
Removed FLAnimatedImage.posterImage
+
Removed FLAnimatedImage.size
+
Removed FLAnimatedImage.loopCount
+
Removed FLAnimatedImage.delayTimesForIndexes
+
Removed FLAnimatedImage.frameCount
+
Removed FLAnimatedImage.frameCacheSizeCurrent
+
Removed FLAnimatedImage.frameCacheSizeMax
+
Removed -[FLAnimatedImage imageLazilyCachedAtIndex:]
+
Removed +[FLAnimatedImage sizeForImage:]
+
Removed -[FLAnimatedImage initWithAnimatedGIFData:]
+
Removed -[FLAnimatedImage initWithAnimatedGIFData:optimalFrameCacheSize:predrawingEnabled:]
+
Removed +[FLAnimatedImage animatedImageWithGIFData:]
+
Removed FLAnimatedImage.data
+
Removed FLLogLevel
+
Removed FLLogLevelNone
+
Removed FLLogLevelError
+
Removed FLLogLevelWarn
+
Removed FLLogLevelInfo
+
Removed FLLogLevelDebug
+
Removed FLLogLevelVerbose
+
Removed +[FLAnimatedImage setLogBlock:logLevel:]
+
Removed +[FLAnimatedImage logStringFromBlock:withLevel:]
+
Removed #def FLLog
+
Removed FLWeakProxy
+
Removed +[FLWeakProxy weakProxyForObject:]
+
+ +
+ +
+
FLAnimatedImageView.h
+ +
+
Removed FLAnimatedImageView
+
Removed FLAnimatedImageView.animatedImage
+
Removed FLAnimatedImageView.loopCompletionBlock
+
Removed FLAnimatedImageView.currentFrame
+
Removed FLAnimatedImageView.currentFrameIndex
+
Removed FLAnimatedImageView.runLoopMode
+
+ +
+
FLAnimatedImageView+WebCache.h
-
Modified -[FLAnimatedImageView sd_setImageWithURL:placeholderImage:options:progress:completed:]
- - - - -
Declaration
From- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock
To- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock
-
+
Removed UIImage (FLAnimatedImage)
+
Removed UIImage.sd_FLAnimatedImage
+
Removed FLAnimatedImageView.sd_optimalFrameCacheSize
+
Removed FLAnimatedImageView.sd_predrawingEnabled
+
Removed FLAnimatedImageView.sd_cacheFLAnimatedImage
+
Removed -[FLAnimatedImageView sd_setImageWithURL:]
+
Removed -[FLAnimatedImageView sd_setImageWithURL:placeholderImage:]
+
Removed -[FLAnimatedImageView sd_setImageWithURL:placeholderImage:options:]
+
Removed -[FLAnimatedImageView sd_setImageWithURL:completed:]
+
Removed -[FLAnimatedImageView sd_setImageWithURL:placeholderImage:completed:]
+
Removed -[FLAnimatedImageView sd_setImageWithURL:placeholderImage:options:completed:]
+
Removed -[FLAnimatedImageView sd_setImageWithURL:placeholderImage:options:progress:completed:]
@@ -24,9 +78,43 @@
MKAnnotationView+WebCache.h
-
Added -[MKAnnotationView sd_setImageWithURL:placeholderImage:options:context:]
-
Added -[MKAnnotationView sd_setImageWithURL:placeholderImage:options:progress:completed:]
-
Added -[MKAnnotationView sd_setImageWithURL:placeholderImage:options:context:progress:completed:]
+
Removed MKAnnotationView (WebCache)
+
Removed -[MKAnnotationView sd_setImageWithURL:]
+
Removed -[MKAnnotationView sd_setImageWithURL:placeholderImage:]
+
Removed -[MKAnnotationView sd_setImageWithURL:placeholderImage:options:]
+
Removed -[MKAnnotationView sd_setImageWithURL:completed:]
+
Removed -[MKAnnotationView sd_setImageWithURL:placeholderImage:completed:]
+
Removed -[MKAnnotationView sd_setImageWithURL:placeholderImage:options:completed:]
+
+ + + +
+
NSData+ImageContentType.h
+ +
+
Removed SDImageFormatUndefined
+
Removed SDImageFormatJPEG
+
Removed SDImageFormatPNG
+
Removed SDImageFormatGIF
+
Removed SDImageFormatTIFF
+
Removed SDImageFormatWebP
+
Removed SDImageFormatHEIC
+
Removed SDImageFormatHEIF
+
Removed +[NSData sd_UTTypeFromSDImageFormat:]
+
+ + +
+
Added SDImageFormatUndefined
+
Added SDImageFormatJPEG
+
Added SDImageFormatPNG
+
Added SDImageFormatGIF
+
Added SDImageFormatTIFF
+
Added SDImageFormatWebP
+
Added SDImageFormatHEIC
+
Added SDImageFormatHEIF
+
Added +[NSData sd_UTTypeFromImageFormat:]
@@ -36,10 +124,11 @@
Added SDAnimatedImage
+
Added -[SDAnimatedImage initWithData:scale:options:]
Added -[SDAnimatedImage initWithAnimatedCoder:scale:]
Added -[SDAnimatedImage preloadAllFrames]
Added -[SDAnimatedImage unloadAllFrames]
-
Added -[SDAnimatedImage isAllFramesLoaded]
+
Added SDAnimatedImage.allFramesLoaded
Added SDAnimatedImage
Added +[SDAnimatedImage imageNamed:]
Added +[SDAnimatedImage imageNamed:inBundle:compatibleWithTraitCollection:]
@@ -49,7 +138,6 @@
Added -[SDAnimatedImage initWithContentsOfFile:]
Added -[SDAnimatedImage initWithData:]
Added -[SDAnimatedImage initWithData:scale:]
-
Added -[SDAnimatedImage initWithAnimatedCoder:scale:]
Added SDAnimatedImage.animatedImageFormat
Added SDAnimatedImage.animatedImageData
Added SDAnimatedImage.scale
@@ -111,6 +199,7 @@
Added -[SDDiskCache totalSize]
Added SDDiskCache
Added SDDiskCache.config
+
Added -[SDDiskCache moveCacheDirectoryFromPath:toPath:]
@@ -304,10 +393,12 @@
Added SDImageCoderOption
Added SDImageCoderOptions
+
Added SDImageCoderMutableOptions
Added SDImageCoderDecodeFirstFrameOnly
Added SDImageCoderDecodeScaleFactor
Added SDImageCoderEncodeFirstFrameOnly
Added SDImageCoderEncodeCompressionQuality
+
Added SDImageCoderWebImageContext
Added SDImageCoder
Added -[SDImageCoder canDecodeFromData:]
Added -[SDImageCoder decodedImageWithData:options:]
@@ -319,9 +410,9 @@
Added -[SDProgressiveImageCoder updateIncrementalData:finished:]
Added -[SDProgressiveImageCoder incrementalDecodedImageWithOptions:]
Added SDAnimatedImageProvider
-
Added -[SDAnimatedImageProvider animatedImageData]
-
Added -[SDAnimatedImageProvider animatedImageFrameCount]
-
Added -[SDAnimatedImageProvider animatedImageLoopCount]
+
Added SDAnimatedImageProvider.animatedImageData
+
Added SDAnimatedImageProvider.animatedImageFrameCount
+
Added SDAnimatedImageProvider.animatedImageLoopCount
Added -[SDAnimatedImageProvider animatedImageFrameAtIndex:]
Added -[SDAnimatedImageProvider animatedImageDurationAtIndex:]
Added SDAnimatedImageCoder
@@ -429,7 +520,7 @@
Added SDTransformedKeyForKey()
Added SDImageTransformer
-
Added -[SDImageTransformer transformerKey]
+
Added SDImageTransformer.transformerKey
Added -[SDImageTransformer transformedImageWithImage:forKey:]
Added SDImagePipelineTransformer
Added SDImagePipelineTransformer.transformers
@@ -576,6 +667,12 @@
Removed #def dispatch_queue_async_safe
+ +
+
Added #def SD_LOCK
+
Added #def SD_UNLOCK
+
+
@@ -596,7 +693,6 @@
Added SDWebImageDecodeFirstFrameOnly
Added SDWebImagePreloadAllFrames
Added SDWebImageContextSetImageOperationKey
-
Added SDWebImageContextSetImageGroup
Added SDWebImageContextCustomManager
Added SDWebImageContextImageTransformer
Added SDWebImageContextImageScaleFactor
@@ -721,6 +817,7 @@
Added SDWebImageDownloaderConfig.defaultDownloaderConfig
Added SDWebImageDownloaderConfig.maxConcurrentDownloads
Added SDWebImageDownloaderConfig.downloadTimeout
+
Added SDWebImageDownloaderConfig.minimumProgressInterval
Added SDWebImageDownloaderConfig.sessionConfiguration
Added SDWebImageDownloaderConfig.operationClass
Added SDWebImageDownloaderConfig.executionOrder
@@ -743,6 +840,7 @@
Removed -[SDWebImageDownloaderOperationInterface credential]
Removed -[SDWebImageDownloaderOperationInterface setCredential:]
Removed -[SDWebImageDownloaderOperationInterface cancel:]
+
Removed -[SDWebImageDownloaderOperationInterface dataTask]
Removed SDWebImageDownloaderOperation.shouldDecompressImages
Removed SDWebImageDownloaderOperation.shouldUseCredentialStorage
Removed SDWebImageDownloaderOperation.expectedSize
@@ -754,12 +852,13 @@
Added -[SDWebImageDownloaderOperation initWithRequest:inSession:options:]
Added -[SDWebImageDownloaderOperation initWithRequest:inSession:options:context:]
Added -[SDWebImageDownloaderOperation addHandlersForProgress:completed:]
-
Added -[SDWebImageDownloaderOperation credential]
-
Added -[SDWebImageDownloaderOperation setCredential:]
Added -[SDWebImageDownloaderOperation cancel:]
-
Added -[SDWebImageDownloaderOperation request]
-
Added -[SDWebImageDownloaderOperation response]
-
Added -[SDWebImageDownloaderOperation dataTask]
+
Added SDWebImageDownloaderOperation.request
+
Added SDWebImageDownloaderOperation.response
+
Added SDWebImageDownloaderOperation.dataTask
+
Added SDWebImageDownloaderOperation.credential
+
Added SDWebImageDownloaderOperation.minimumProgressInterval
+
Added SDWebImageDownloaderOperation.minimumProgressInterval
Added SDWebImageDownloaderOperation.context
Added -[SDWebImageDownloaderOperation initWithRequest:inSession:options:context:]
@@ -769,7 +868,7 @@
Modified SDWebImageDownloaderOperation
- +
Protocols
FromNSURLSessionDataDelegate, NSURLSessionTaskDelegate, SDWebImageDownloaderOperationInterface, SDWebImageOperation
FromSDWebImageDownloaderOperationInterface, SDWebImageOperation
ToSDWebImageDownloaderOperation

@@ -861,7 +960,7 @@
Added SDWebImageIndicator
-
Added -[SDWebImageIndicator indicatorView]
+
Added SDWebImageIndicator.indicatorView
Added -[SDWebImageIndicator startAnimatingIndicator]
Added -[SDWebImageIndicator stopAnimatingIndicator]
Added -[SDWebImageIndicator updateIndicatorProgress:]
@@ -1155,6 +1254,8 @@
Removed -[UIImageView sd_setImageWithPreviousCachedImageWithURL:placeholderImage:options:progress:completed:]
+
Removed -[UIImageView sd_setAnimationImagesWithURLs:]
+
Removed -[UIImageView sd_cancelCurrentAnimationImagesLoad]
@@ -1199,6 +1300,13 @@
+
Modified SDSetImageBlock
+ + + + +
Declaration
Fromtypedef void (^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable imageData)
Totypedef void (^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL)
+
Modified -[UIView sd_imageURL]
From 9d7b82f1fba035eb1bdf27c2283a9315e659eb75 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Sat, 27 Oct 2018 18:44:40 +0800 Subject: [PATCH 276/361] Replace atomic property with SD_LOCK Replace atomic property with SD_LOCK fix LOCK not decrease --- SDWebImage/SDWebImageDownloader.h | 2 +- SDWebImage/SDWebImageDownloader.m | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 351d57d1..b223d4ec 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -171,7 +171,7 @@ typedef SDImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock; /** * Set a value for a HTTP header to be appended to each download HTTP request. * - * @param value The value for the header field. Use `nil` value to remove the header. + * @param value The value for the header field. Use `nil` value to remove the header field. * @param field The name of the header field to set. */ - (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field; diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 2b9edebf..9d56381a 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -34,8 +34,9 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; @property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue; @property (weak, nonatomic, nullable) NSOperation *lastAddedOperation; @property (strong, nonatomic, nonnull) NSMutableDictionary *> *URLOperations; -@property (copy, atomic, nullable) NSDictionary *HTTPHeaders; // Since modify this value is rare, use immutable object can enhance performance. But should mark as atomic to keep thread-safe -@property (strong, nonatomic, nonnull) dispatch_semaphore_t operationsLock; // a lock to keep the access to `URLOperations` thread-safe +@property (strong, nonatomic, nullable) NSMutableDictionary *HTTPHeaders; +@property (strong, nonatomic, nonnull) dispatch_semaphore_t HTTPHeadersLock; // A lock to keep the access to `HTTPHeaders` thread-safe +@property (strong, nonatomic, nonnull) dispatch_semaphore_t operationsLock; // A lock to keep the access to `URLOperations` thread-safe // The session in which data tasks will run @property (strong, nonatomic) NSURLSession *session; @@ -113,7 +114,8 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; headerDictionary[@"User-Agent"] = userAgent; } headerDictionary[@"Accept"] = @"image/*;q=0.8"; - _HTTPHeaders = [headerDictionary copy]; + _HTTPHeaders = headerDictionary; + _HTTPHeadersLock = dispatch_semaphore_create(1); _operationsLock = dispatch_semaphore_create(1); NSURLSessionConfiguration *sessionConfiguration = _config.sessionConfiguration; if (!sessionConfiguration) { @@ -154,16 +156,19 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; if (!field) { return; } - NSMutableDictionary *mutableHTTPHeaders = [self.HTTPHeaders mutableCopy]; - [mutableHTTPHeaders setValue:value forKey:field]; - self.HTTPHeaders = [mutableHTTPHeaders copy]; + SD_LOCK(self.HTTPHeadersLock); + [self.HTTPHeaders setValue:value forKey:field]; + SD_UNLOCK(self.HTTPHeadersLock); } - (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field { if (!field) { return nil; } - return [self.HTTPHeaders objectForKey:field]; + SD_LOCK(self.HTTPHeadersLock); + NSString *value = [self.HTTPHeaders objectForKey:field]; + SD_UNLOCK(self.HTTPHeadersLock); + return value; } - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock { @@ -238,7 +243,9 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:cachePolicy timeoutInterval:timeoutInterval]; mutableRequest.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies); mutableRequest.HTTPShouldUsePipelining = YES; + SD_LOCK(self.HTTPHeadersLock); mutableRequest.allHTTPHeaderFields = self.HTTPHeaders; + SD_UNLOCK(self.HTTPHeadersLock); id requestModifier; if ([context valueForKey:SDWebImageContextDownloadRequestModifier]) { requestModifier = [context valueForKey:SDWebImageContextDownloadRequestModifier]; From 67499263a819b24ab77cdcbe2b68edbc8ad1a3c5 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 29 Oct 2018 12:52:17 +0800 Subject: [PATCH 277/361] Fix the accident changes of Swift API naming for `sd_imageDataAsFormat:`. We should keep previous naming `sd_imageData(as:)` --- SDWebImage/UIImage+MultiFormat.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SDWebImage/UIImage+MultiFormat.h b/SDWebImage/UIImage+MultiFormat.h index 951d66a5..d3496582 100644 --- a/SDWebImage/UIImage+MultiFormat.h +++ b/SDWebImage/UIImage+MultiFormat.h @@ -52,7 +52,7 @@ @param imageFormat The specify image format @return The encoded data. If can't encode, return nil */ -- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat; +- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat NS_SWIFT_NAME(sd_imageData(as:)); /** Encode the current image to data with the specify image format and compression quality @@ -61,7 +61,7 @@ @param compressionQuality The quality of the resulting image data. Value between 0.0-1.0. Some coders may not support compression quality. @return The encoded data. If can't encode, return nil */ -- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat compressionQuality:(double)compressionQuality; +- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat compressionQuality:(double)compressionQuality NS_SWIFT_NAME(sd_imageData(as:compressionQuality:)); /** Encode the current image to data with the specify image format and compression quality, allow specify animate/static control @@ -71,6 +71,6 @@ @param firstFrameOnly Even if the image is animated image, encode the first frame only as static image. @return The encoded data. If can't encode, return nil */ -- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat compressionQuality:(double)compressionQuality firstFrameOnly:(BOOL)firstFrameOnly; +- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat compressionQuality:(double)compressionQuality firstFrameOnly:(BOOL)firstFrameOnly NS_SWIFT_NAME(sd_imageData(as:compressionQuality:firstFrameOnly:)); @end From ee6f99f204d878b01be5b17fd0d3a0f47c69d005 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 31 Oct 2018 14:40:10 +0800 Subject: [PATCH 278/361] Fix that the graphics helper method will return nil when scale = 0, match the UIKit behavior --- SDWebImage/UIImage+Transform.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index ff95ea45..a397924a 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -18,6 +18,10 @@ static void *kNSGraphicsContextScaleFactorKey; static CGContextRef SDCGContextCreateBitmapContext(CGSize size, BOOL opaque, CGFloat scale) { + if (scale == 0) { + // Match `UIGraphicsBeginImageContextWithOptions`, reset to the scale factor of the device’s main screen if scale is 0. + scale = [NSScreen mainScreen].backingScaleFactor; + } size_t width = ceil(size.width * scale); size_t height = ceil(size.height * scale); if (width < 1 || height < 1) return NULL; @@ -30,10 +34,6 @@ static CGContextRef SDCGContextCreateBitmapContext(CGSize size, BOOL opaque, CGF if (!context) { return NULL; } - if (scale == 0) { - // Match `UIGraphicsBeginImageContextWithOptions`, reset to the scale factor of the device’s main screen if scale is 0. - scale = [NSScreen mainScreen].backingScaleFactor; - } CGContextScaleCTM(context, scale, scale); return context; From 025c5f833b7a73076562df9c839333c0cdb2d1ee Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 31 Oct 2018 15:13:31 +0800 Subject: [PATCH 279/361] Expose the all image graphics methods to public method, make it easy for coder plugin user to reuse it instead of duplicate code --- SDWebImage.xcodeproj/project.pbxproj | 16 ++++ SDWebImage/SDImageGraphics.h | 21 ++++++ SDWebImage/SDImageGraphics.m | 105 +++++++++++++++++++++++++++ SDWebImage/UIImage+Transform.m | 88 +--------------------- WebImage/SDWebImage.h | 1 + 5 files changed, 144 insertions(+), 87 deletions(-) create mode 100644 SDWebImage/SDImageGraphics.h create mode 100644 SDWebImage/SDImageGraphics.m diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index c2186d66..2b7a7135 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -57,6 +57,12 @@ 325312CA200F09910046BF1E /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 325312C6200F09910046BF1E /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; }; 325312CE200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; }; 325312D0200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; }; + 3257EAF921898AED0097B271 /* SDImageGraphics.h in Headers */ = {isa = PBXBuildFile; fileRef = 3257EAF721898AED0097B271 /* SDImageGraphics.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3257EAFA21898AED0097B271 /* SDImageGraphics.h in Headers */ = {isa = PBXBuildFile; fileRef = 3257EAF721898AED0097B271 /* SDImageGraphics.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3257EAFB21898AED0097B271 /* SDImageGraphics.h in Headers */ = {isa = PBXBuildFile; fileRef = 3257EAF721898AED0097B271 /* SDImageGraphics.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3257EAFC21898AED0097B271 /* SDImageGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3257EAF821898AED0097B271 /* SDImageGraphics.m */; }; + 3257EAFD21898AED0097B271 /* SDImageGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3257EAF821898AED0097B271 /* SDImageGraphics.m */; }; + 3257EAFE21898AED0097B271 /* SDImageGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3257EAF821898AED0097B271 /* SDImageGraphics.m */; }; 327054D4206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 327054D6206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 327054DA206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; }; @@ -243,6 +249,8 @@ 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDefine.m; sourceTree = ""; }; 325312C6200F09910046BF1E /* SDWebImageTransition.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTransition.h; sourceTree = ""; }; 325312C7200F09910046BF1E /* SDWebImageTransition.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransition.m; sourceTree = ""; }; + 3257EAF721898AED0097B271 /* SDImageGraphics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageGraphics.h; sourceTree = ""; }; + 3257EAF821898AED0097B271 /* SDImageGraphics.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageGraphics.m; sourceTree = ""; }; 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageAPNGCoder.h; sourceTree = ""; }; 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageAPNGCoder.m; sourceTree = ""; }; 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCacheKeyFilter.h; sourceTree = ""; }; @@ -369,6 +377,8 @@ 3290FA031FA478AF0047D20C /* SDImageFrame.m */, 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */, 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */, + 3257EAF721898AED0097B271 /* SDImageGraphics.h */, + 3257EAF821898AED0097B271 /* SDImageGraphics.m */, ); name = Decoder; sourceTree = ""; @@ -603,6 +613,7 @@ files = ( 32D122202080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, + 3257EAFA21898AED0097B271 /* SDImageGraphics.h in Headers */, 328BB6AC2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 321B378F2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, 329A185B1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, @@ -658,6 +669,7 @@ files = ( 32CF1C071FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, 32F7C0842030719600873181 /* UIImage+Transform.h in Headers */, + 3257EAF921898AED0097B271 /* SDImageGraphics.h in Headers */, 53761316155AD0D5005750A4 /* SDImageCache.h in Headers */, 325312C8200F09910046BF1E /* SDWebImageTransition.h in Headers */, 32C0FDE12013426C001B8F2D /* SDWebImageIndicator.h in Headers */, @@ -711,6 +723,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 3257EAFB21898AED0097B271 /* SDImageGraphics.h in Headers */, 806BE07E2142C65200E02143 /* SDWebImageMapKit.h in Headers */, 80B6DFCD2142B71600BCB334 /* MKAnnotationView+WebCache.h in Headers */, ); @@ -846,6 +859,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3257EAFD21898AED0097B271 /* SDImageGraphics.m in Sources */, 3290FA0C1FA478AF0047D20C /* SDImageFrame.m in Sources */, 321E60C61F38E91700405457 /* UIImage+ForceDecode.m in Sources */, 328BB6A42081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, @@ -899,6 +913,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3257EAFC21898AED0097B271 /* SDImageGraphics.m in Sources */, 3290FA0A1FA478AF0047D20C /* SDImageFrame.m in Sources */, 321E60C41F38E91700405457 /* UIImage+ForceDecode.m in Sources */, 328BB6A22081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, @@ -953,6 +968,7 @@ buildActionMask = 2147483647; files = ( 80B6DFA72142B71600BCB334 /* MKAnnotationView+WebCache.m in Sources */, + 3257EAFE21898AED0097B271 /* SDImageGraphics.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SDWebImage/SDImageGraphics.h b/SDWebImage/SDImageGraphics.h new file mode 100644 index 00000000..6a41e9a2 --- /dev/null +++ b/SDWebImage/SDImageGraphics.h @@ -0,0 +1,21 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import + +/** + These following graphics context method are provided to easily write cross-platform(AppKit/UIKit) code. + For UIKit, these methods just call the same method in `UIGraphics.h`. See the documentation for usage. + For AppKit, these methods use `NSGraphicsContext` to create image context and match the behavior like UIKit. + */ +FOUNDATION_EXPORT CGContextRef __nullable SDGraphicsGetCurrentContext(void) CF_RETURNS_NOT_RETAINED; +FOUNDATION_EXPORT void SDGraphicsBeginImageContext(CGSize size); +FOUNDATION_EXPORT void SDGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale); +FOUNDATION_EXPORT void SDGraphicsEndImageContext(void); +FOUNDATION_EXPORT UIImage * __nullable SDGraphicsGetImageFromCurrentImageContext(void); diff --git a/SDWebImage/SDImageGraphics.m b/SDWebImage/SDImageGraphics.m new file mode 100644 index 00000000..683780ee --- /dev/null +++ b/SDWebImage/SDImageGraphics.m @@ -0,0 +1,105 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDImageGraphics.h" +#import "NSImage+Compatibility.h" +#import "objc/runtime.h" + +#if SD_MAC +static void *kNSGraphicsContextScaleFactorKey; + +static CGContextRef SDCGContextCreateBitmapContext(CGSize size, BOOL opaque, CGFloat scale) { + if (scale == 0) { + // Match `UIGraphicsBeginImageContextWithOptions`, reset to the scale factor of the device’s main screen if scale is 0. + scale = [NSScreen mainScreen].backingScaleFactor; + } + size_t width = ceil(size.width * scale); + size_t height = ceil(size.height * scale); + if (width < 1 || height < 1) return NULL; + + //pre-multiplied BGRA for non-opaque, BGRX for opaque, 8-bits per component, as Apple's doc + CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); + CGImageAlphaInfo alphaInfo = kCGBitmapByteOrder32Host | (opaque ? kCGImageAlphaNoneSkipFirst : kCGImageAlphaPremultipliedFirst); + CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, space, kCGBitmapByteOrderDefault | alphaInfo); + CGColorSpaceRelease(space); + if (!context) { + return NULL; + } + CGContextScaleCTM(context, scale, scale); + + return context; +} +#endif + +CGContextRef SDGraphicsGetCurrentContext(void) { +#if SD_UIKIT || SD_WATCH + return UIGraphicsGetCurrentContext(); +#else + return NSGraphicsContext.currentContext.CGContext; +#endif +} + +void SDGraphicsBeginImageContext(CGSize size) { +#if SD_UIKIT || SD_WATCH + SDGraphicsBeginImageContext(size); +#else + SDGraphicsBeginImageContextWithOptions(size, NO, 1.0); +#endif +} + +void SDGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale) { +#if SD_UIKIT || SD_WATCH + UIGraphicsBeginImageContextWithOptions(size, opaque, scale); +#else + CGContextRef context = SDCGContextCreateBitmapContext(size, opaque, scale); + if (!context) { + return; + } + NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithCGContext:context flipped:NO]; + objc_setAssociatedObject(graphicsContext, &kNSGraphicsContextScaleFactorKey, @(scale), OBJC_ASSOCIATION_RETAIN); + CGContextRelease(context); + [NSGraphicsContext saveGraphicsState]; + NSGraphicsContext.currentContext = graphicsContext; +#endif +} + +void SDGraphicsEndImageContext(void) { +#if SD_UIKIT || SD_WATCH + UIGraphicsEndImageContext(); +#else + [NSGraphicsContext restoreGraphicsState]; +#endif +} + +UIImage * SDGraphicsGetImageFromCurrentImageContext(void) { +#if SD_UIKIT || SD_WATCH + return UIGraphicsGetImageFromCurrentImageContext(); +#else + NSGraphicsContext *context = NSGraphicsContext.currentContext; + CGContextRef contextRef = context.CGContext; + if (!contextRef) { + return nil; + } + CGImageRef imageRef = CGBitmapContextCreateImage(contextRef); + if (!imageRef) { + return nil; + } + CGFloat scale = 0; + NSNumber *scaleFactor = objc_getAssociatedObject(context, &kNSGraphicsContextScaleFactorKey); + if ([scaleFactor isKindOfClass:[NSNumber class]]) { + scale = scaleFactor.doubleValue; + } + if (!scale) { + // reset to the scale factor of the device’s main screen if scale is 0. + scale = [NSScreen mainScreen].backingScaleFactor; + } + NSImage *image = [[NSImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp]; + CGImageRelease(imageRef); + return image; +#endif +} diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index a397924a..6d844ec9 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -8,98 +8,12 @@ #import "UIImage+Transform.h" #import "NSImage+Compatibility.h" +#import "SDImageGraphics.h" #import #if SD_UIKIT || SD_MAC #import -#import "objc/runtime.h" #endif -#if SD_MAC -static void *kNSGraphicsContextScaleFactorKey; - -static CGContextRef SDCGContextCreateBitmapContext(CGSize size, BOOL opaque, CGFloat scale) { - if (scale == 0) { - // Match `UIGraphicsBeginImageContextWithOptions`, reset to the scale factor of the device’s main screen if scale is 0. - scale = [NSScreen mainScreen].backingScaleFactor; - } - size_t width = ceil(size.width * scale); - size_t height = ceil(size.height * scale); - if (width < 1 || height < 1) return NULL; - - //pre-multiplied BGRA for non-opaque, BGRX for opaque, 8-bits per component, as Apple's doc - CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); - CGImageAlphaInfo alphaInfo = kCGBitmapByteOrder32Host | (opaque ? kCGImageAlphaNoneSkipFirst : kCGImageAlphaPremultipliedFirst); - CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, space, kCGBitmapByteOrderDefault | alphaInfo); - CGColorSpaceRelease(space); - if (!context) { - return NULL; - } - CGContextScaleCTM(context, scale, scale); - - return context; -} -#endif - -static void SDGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale) { -#if SD_UIKIT || SD_WATCH - UIGraphicsBeginImageContextWithOptions(size, opaque, scale); -#else - CGContextRef context = SDCGContextCreateBitmapContext(size, opaque, scale); - if (!context) { - return; - } - NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithCGContext:context flipped:NO]; - objc_setAssociatedObject(graphicsContext, &kNSGraphicsContextScaleFactorKey, @(scale), OBJC_ASSOCIATION_RETAIN); - CGContextRelease(context); - [NSGraphicsContext saveGraphicsState]; - NSGraphicsContext.currentContext = graphicsContext; -#endif -} - -static CGContextRef SDGraphicsGetCurrentContext(void) { -#if SD_UIKIT || SD_WATCH - return UIGraphicsGetCurrentContext(); -#else - return NSGraphicsContext.currentContext.CGContext; -#endif -} - -static void SDGraphicsEndImageContext(void) { -#if SD_UIKIT || SD_WATCH - UIGraphicsEndImageContext(); -#else - [NSGraphicsContext restoreGraphicsState]; -#endif -} - -static UIImage * SDGraphicsGetImageFromCurrentImageContext(void) { -#if SD_UIKIT || SD_WATCH - return UIGraphicsGetImageFromCurrentImageContext(); -#else - NSGraphicsContext *context = NSGraphicsContext.currentContext; - CGContextRef contextRef = context.CGContext; - if (!contextRef) { - return nil; - } - CGImageRef imageRef = CGBitmapContextCreateImage(contextRef); - if (!imageRef) { - return nil; - } - CGFloat scale = 0; - NSNumber *scaleFactor = objc_getAssociatedObject(context, &kNSGraphicsContextScaleFactorKey); - if ([scaleFactor isKindOfClass:[NSNumber class]]) { - scale = scaleFactor.doubleValue; - } - if (!scale) { - // reset to the scale factor of the device’s main screen if scale is 0. - scale = [NSScreen mainScreen].backingScaleFactor; - } - NSImage *image = [[NSImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp]; - CGImageRelease(imageRef); - return image; -#endif -} - static inline CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMode scaleMode) { rect = CGRectStandardize(rect); size.width = size.width < 0 ? -size.width : size.width; diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index ce50a1f3..49eeae80 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -59,6 +59,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import +#import #import #import #import From 5d097bbc8d9ea5b9b972510831a253c99da5731e Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 1 Nov 2018 11:18:14 +0800 Subject: [PATCH 280/361] Fix the `SDGraphicsBeginImageContext` method recursive call issue --- SDWebImage/SDImageGraphics.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/SDImageGraphics.m b/SDWebImage/SDImageGraphics.m index 683780ee..e7c4ed45 100644 --- a/SDWebImage/SDImageGraphics.m +++ b/SDWebImage/SDImageGraphics.m @@ -46,7 +46,7 @@ CGContextRef SDGraphicsGetCurrentContext(void) { void SDGraphicsBeginImageContext(CGSize size) { #if SD_UIKIT || SD_WATCH - SDGraphicsBeginImageContext(size); + UIGraphicsBeginImageContext(size); #else SDGraphicsBeginImageContextWithOptions(size, NO, 1.0); #endif From edb9c45859698edb91ea399a1ab576ecff2b9e05 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Sun, 23 Sep 2018 14:34:27 +0300 Subject: [PATCH 281/361] Xcode 10 - upgraded schemes, using xcode10 Travis image, removed some deprecated methods from our demos + formatting Using xcconfig files - easier to maintain all the settings appart from target files, less conflicts, can reuse the values --- Configs/App-Debug.xcconfig | 8 + Configs/App-Release.xcconfig | 11 + Configs/App-Shared.xcconfig | 10 + Configs/Module-Debug.xcconfig | 31 + Configs/Module-Release.xcconfig | 28 + Configs/Module-Shared.xcconfig | 228 ++++++ .../SDWebImage Demo.xcodeproj/project.pbxproj | 754 ++++++------------ .../xcschemes/SDWebImage OSX Demo.xcscheme | 2 +- .../xcschemes/SDWebImage TV Demo.xcscheme | 2 +- .../xcschemes/SDWebImage Watch Demo.xcscheme | 2 +- .../xcschemes/SDWebImage iOS Demo.xcscheme | 2 +- .../SDWebImage Demo/MasterViewController.m | 4 - .../Content.imageset/Contents.json | 4 + .../Content.imageset/Contents.json | 4 + .../Content.imageset/Contents.json | 4 + .../Content.imageset/Contents.json | 4 + .../Content.imageset/Contents.json | 4 + .../Content.imageset/Contents.json | 4 + .../Contents.json | 8 +- .../Contents.json | 16 + .../Top Shelf Image.imageset/Contents.json | 4 + .../LaunchImage.launchimage/Contents.json | 7 + .../AppIcon.appiconset/Contents.json | 28 +- SDWebImage.xcodeproj/project.pbxproj | 182 +---- .../xcschemes/SDWebImage static.xcscheme | 6 +- .../xcschemes/SDWebImage.xcscheme | 2 +- .../xcschemes/SDWebImageMapKit.xcscheme | 2 +- SDWebImage/SDAnimatedImageRep.m | 3 + .../project.pbxproj | 346 +++----- .../xcshareddata/xcschemes/Tests Mac.xcscheme | 2 +- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 31 files changed, 790 insertions(+), 924 deletions(-) create mode 100644 Configs/App-Debug.xcconfig create mode 100644 Configs/App-Release.xcconfig create mode 100644 Configs/App-Shared.xcconfig create mode 100644 Configs/Module-Debug.xcconfig create mode 100644 Configs/Module-Release.xcconfig create mode 100644 Configs/Module-Shared.xcconfig create mode 100644 Examples/SDWebImage TV Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json diff --git a/Configs/App-Debug.xcconfig b/Configs/App-Debug.xcconfig new file mode 100644 index 00000000..2043ccce --- /dev/null +++ b/Configs/App-Debug.xcconfig @@ -0,0 +1,8 @@ +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +#include "Module-Debug.xcconfig" +#include "App-Shared.xcconfig" + +// If enabled, only the active architecture is built. +ONLY_ACTIVE_ARCH = YES diff --git a/Configs/App-Release.xcconfig b/Configs/App-Release.xcconfig new file mode 100644 index 00000000..e4118dc7 --- /dev/null +++ b/Configs/App-Release.xcconfig @@ -0,0 +1,11 @@ +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +#include "Module-Release.xcconfig" +#include "App-Shared.xcconfig" + +// If enabled, only the active architecture is built. +ONLY_ACTIVE_ARCH = NO + +// Space-separated list of additional flags to pass to the compiler for C and Objective-C files. Be sure to backslash-escape any arguments that contain spaces or special characters, such as path names that may contain spaces. Use this setting if Xcode does not already provide UI for a particular C or Objective-C compiler flag. +OTHER_CFLAGS = -DNS_BLOCK_ASSERTIONS=1 diff --git a/Configs/App-Shared.xcconfig b/Configs/App-Shared.xcconfig new file mode 100644 index 00000000..351625b0 --- /dev/null +++ b/Configs/App-Shared.xcconfig @@ -0,0 +1,10 @@ +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +#include "Module-Shared.xcconfig" + +// Name of an asset catalog app icon set whose contents will be merged into the `Info.plist`. +ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon + +// The compiler to use for C, C++, and Objective-C. +GCC_VERSION = \ No newline at end of file diff --git a/Configs/Module-Debug.xcconfig b/Configs/Module-Debug.xcconfig new file mode 100644 index 00000000..7a80c401 --- /dev/null +++ b/Configs/Module-Debug.xcconfig @@ -0,0 +1,31 @@ +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +#include "Module-Shared.xcconfig" + +// Specifies whether binary files that are copied during the build, such as in a Copy Bundle Resources or Copy Files build phase, should be stripped of debugging symbols. +COPY_PHASE_STRIP = NO + +// The type of debug information to produce. +DEBUG_INFORMATION_FORMAT = dwarf + +// Controls whether assertion logic provided by `NSAssert` is included in the preprocessed source code or is elided during preprocessing. +ENABLE_NS_ASSERTIONS = YES + +// When this setting is activated, the product will be built with options appropriate for running automated tests, such as making private interfaces accessible to the tests. +ENABLE_TESTABILITY = YES + +// Specifies the degree to which the generated code is optimized for speed and binary size. +GCC_OPTIMIZATION_LEVEL = 0 + +// Space-separated list of preprocessor macros of the form `foo` or `foo=bar` +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) DEBUG=1 + +// Metal debug info - not sure why we need it +MTL_ENABLE_DEBUG_INFO = YES + +// If enabled, only the active architecture is built. +ONLY_ACTIVE_ARCH = YES + +// If enabled, perform validation checks on the product as part of the build process. +VALIDATE_PRODUCT = NO diff --git a/Configs/Module-Release.xcconfig b/Configs/Module-Release.xcconfig new file mode 100644 index 00000000..30e86635 --- /dev/null +++ b/Configs/Module-Release.xcconfig @@ -0,0 +1,28 @@ +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +#include "Module-Shared.xcconfig" + +// Specifies whether binary files that are copied during the build, such as in a Copy Bundle Resources or Copy Files build phase, should be stripped of debugging symbols. +COPY_PHASE_STRIP = YES + +// The type of debug information to produce. +DEBUG_INFORMATION_FORMAT = dwarf-with-dsym + +// Controls whether assertion logic provided by `NSAssert` is included in the preprocessed source code or is elided during preprocessing. +ENABLE_NS_ASSERTIONS = NO + +// When this setting is activated, the product will be built with options appropriate for running automated tests, such as making private interfaces accessible to the tests. +ENABLE_TESTABILITY = NO + +// Specifies the degree to which the generated code is optimized for speed and binary size. +GCC_OPTIMIZATION_LEVEL = s + +// Metal debug info +MTL_ENABLE_DEBUG_INFO = NO + +// If enabled, only the active architecture is built. +ONLY_ACTIVE_ARCH = NO + +// If enabled, perform validation checks on the product as part of the build process. +VALIDATE_PRODUCT = YES diff --git a/Configs/Module-Shared.xcconfig b/Configs/Module-Shared.xcconfig new file mode 100644 index 00000000..7b427751 --- /dev/null +++ b/Configs/Module-Shared.xcconfig @@ -0,0 +1,228 @@ +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +// This setting is deprecated as of Xcode 8.3 and may not be supported in future versions. It is recommended that you disable the setting. If enabled, both `#include `-style and `#include "header.h"`-style directives search the paths in `USER_HEADER_SEARCH_PATHS` before `HEADER_SEARCH_PATHS` +ALWAYS_SEARCH_USER_PATHS = NO + +// Warn for missing nullability attributes +CLANG_ANALYZER_NONNULL = YES + +// Warn when a number object, such as an instance of `NSNumber`, `CFNumberRef`, `OSNumber`, or `OSBoolean` is compared or converted to a primitive value instead of another object. +CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE + +// Choose a standard or non-standard C++ language dialect. +CLANG_CXX_LANGUAGE_STANDARD = gnu++0x + +// Choose a version of the C++ standard library to use. +CLANG_CXX_LIBRARY = libc++ + +// Enables the use of modules for system APIs. System headers are imported as semantic modules instead of raw headers. +CLANG_ENABLE_MODULES = YES + +// Compiles reference-counted Objective-C code (when garbage collection is not enabled) to use Automatic Reference Counting. +CLANG_ENABLE_OBJC_ARC = YES + +// Warn about block captures of implicitly autoreleasing parameters. +CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES + +// Warn about implicit conversions to boolean values that are suspicious. For example, writing `if (foo)` where `foo` is the name a function will trigger a warning. +CLANG_WARN_BOOL_CONVERSION = YES + +// Warn about suspicious uses of the comma operator. +CLANG_WARN_COMMA = YES + +// Warn about implicit conversions of constant values that cause the constant value to change, either through a loss of precision, or entirely in its meaning. +CLANG_WARN_CONSTANT_CONVERSION = YES + +// Warn if an Objective-C class either subclasses a deprecated class or overrides a method that has been marked deprecated or unavailable. +CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES + +// Warn about direct accesses to the Objective-C `isa` pointer instead of using a runtime API. +CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR + +// Warns about issues in documentation comments (`doxygen`-style) such as missing or incorrect documentation tags. +CLANG_WARN_DOCUMENTATION_COMMENTS = YES + +// Warn about declaring the same method more than once within the same `@interface`. +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES + +// Warn about loop bodies that are suspiciously empty. +CLANG_WARN_EMPTY_BODY = YES + +// Warn about implicit conversions between different kinds of enum values. For example, this can catch issues when using the wrong enum flag as an argument to a function or method. +CLANG_WARN_ENUM_CONVERSION = YES + +// Warn if all paths through a function call itself. +CLANG_WARN_INFINITE_RECURSION = YES + +// Warn about implicit conversions between pointers and integers. For example, this can catch issues when one incorrectly intermixes using `NSNumber*`'s and raw integers. +CLANG_WARN_INT_CONVERSION = YES + +// Warn about non-literal expressions that evaluate to zero being treated as a null pointer. +CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES + +// Warn about `@property` declarations that are implicitly atomic. +CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = NO + +// Warn about implicit retains of `self` within blocks, which can create a retain-cycle. +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES + +// Warn about implicit conversions from Objective-C literals to values of incompatible type. +CLANG_WARN_OBJC_LITERAL_CONVERSION = YES + +// Warn about classes that unintentionally do not subclass a root class, such as `NSObject`. +CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR + +// Warn about ranged-based for loops. +CLANG_WARN_RANGE_LOOP_ANALYSIS = YES + +// Warn about non-prototype declarations. +CLANG_WARN_STRICT_PROTOTYPES = YES + +// Warn about suspicious uses of `std::move`. +CLANG_WARN_SUSPICIOUS_MOVE = YES + +// Warn if an API that is newer than the deployment target is used without "if (@available(...))" guards. +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE + +// Warns about potentially unreachable code. +CLANG_WARN_UNREACHABLE_CODE = YES + +// The path to a file specifying code-signing entitlements. +CODE_SIGN_ENTITLEMENTS = + +// The name, also known as the *common name*, of a valid code-signing certificate in a keychain within your keychain path. A missing or invalid certificate will cause a build error. +CODE_SIGN_IDENTITY = + +// This setting defines the current version of the project. The value must be a integer or floating point number, such as `57` or `365.8`. +CURRENT_PROJECT_VERSION = 1 + +// If enabled, the product will be treated as defining its own module. This enables automatic production of LLVM module map files when appropriate, and allows the product to be imported as a module. +DEFINES_MODULE = YES + +// Determines the compatibility version of the resulting library, bundle, or framework binary. +DYLIB_COMPATIBILITY_VERSION = 1 + +// This setting defines the current version of any framework built by the project. As with `CURRENT_PROJECT_VERSION`, the value must be an integer or floating point number, such as `57` or `365.8`. +DYLIB_CURRENT_VERSION = 1 + +// Sets the base value for the internal `install path` (`LC_ID_DYLIB`) in a dynamic library. This will be combined with the `EXECUTABLE_PATH` to form the full install path. +DYLIB_INSTALL_NAME_BASE = @rpath + +// Activating this setting indicates that the target or project should generate bitcode during compilation for platforms and architectures that support it. For Archive builds, bitcode will be generated in the linked binary for submission to the App Store. For other builds, the compiler and linker will check whether the code complies with the requirements for bitcode generation, but will not generate actual bitcode. +ENABLE_BITCODE = YES + +// Controls whether `objc_msgSend` calls must be cast to the appropriate function pointer type before being called. +ENABLE_STRICT_OBJC_MSGSEND = YES + +// This is a list of paths to folders containing frameworks to be searched by the compiler for both included or imported header files when compiling C, Objective-C, C++, or Objective-C++, and by the linker for frameworks used by the product. Paths are delimited by whitespace, so any paths with spaces in them must be properly quoted. +FRAMEWORK_SEARCH_PATHS = $(inherited) + +// Choose a standard or non-standard C language dialect. +GCC_C_LANGUAGE_STANDARD = gnu99 + +// Faster function calls for applications. Not appropriate for shared libraries, which need to be position-independent. +GCC_DYNAMIC_NO_PIC = NO + +// In C, allocate even uninitialized global variables in the data section of the object file, rather than generating them as common blocks. +GCC_NO_COMMON_BLOCKS = YES + +// When enabled, all symbols are declared `private extern` unless explicitly marked to be exported using `\_\_attribute\_\_((visibility("default")))` in code. If not enabled, all symbols are exported unless explicitly marked as `private extern`. +GCC_SYMBOLS_PRIVATE_EXTERN = NO + +// Enabling this option causes all warnings to be treated as errors. +GCC_TREAT_WARNINGS_AS_ERRORS = NO + +// Warn if a value is implicitly converted from a 64-bit type to a 32-bit type. This is a subset of the warnings provided by -Wconversion. +GCC_WARN_64_TO_32_BIT_CONVERSION = YES + +// Warn if a structure's initializer has some fields missing. +GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES + +// Warn when a source file does not end with a newline. +GCC_WARN_ABOUT_MISSING_NEWLINE = YES + +// Causes warnings to be emitted about missing prototypes. +GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES + +// Causes warnings to be emitted when a function with a defined return type (not `void`) contains a return statement without a return-value. Also emits a warning when a function is defined without specifying a return type. +GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR + +// Warn if an aggregate or union initializer is not fully bracketed. +GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES + +// Warn whenever a local variable shadows another local variable, parameter or global variable or whenever a builtin function is shadowed. +GCC_WARN_SHADOW = YES + +// Warn when a comparison between signed and unsigned values could produce an incorrect result when the signed value is converted to unsigned. +GCC_WARN_SIGN_COMPARE = YES + +// Warn if a `@selector(...)` expression referring to an undeclared selector is found. A selector is considered undeclared if no method with that name has been declared before the `@selector(...)` expression, either explicitly in an `@interface` or `@protocol` declaration, or implicitly in an `@implementation` section. +GCC_WARN_UNDECLARED_SELECTOR = YES + +// Warn if a variable might be clobbered by a `setjmp` call or if an automatic variable is used without prior initialization. The compiler may not detect all cases where an automatic variable is initialized or all usage patterns that may lead to use prior to initialization. +GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE + +// Warn whenever a static function is declared but not defined or a noninline static function is unused. +GCC_WARN_UNUSED_FUNCTION = YES + +// Warn whenever a label is declared but not used. +GCC_WARN_UNUSED_LABEL = YES + +// Warn whenever a function parameter is unused aside from its declaration. +GCC_WARN_UNUSED_PARAMETER = NO + +// Warn whenever a local variable or nonconstant static variable is unused aside from its declaration. +GCC_WARN_UNUSED_VARIABLE = YES + +// This is a list of paths to folders to be searched by the compiler for included or imported header files when compiling C, Objective-C, C++, or Objective-C++. Paths are delimited by whitespace, so any paths with spaces in them need to be properly quoted. +HEADER_SEARCH_PATHS = $(inherited) + +// Code will load on this and later versions of iOS. Framework APIs that are unavailable in earlier versions will be weak-linked; your code should check for null function pointers or specific system versions before calling newer APIs. +IPHONEOS_DEPLOYMENT_TARGET = 8.0 + +// This is a list of paths to be added to the `runpath` search path list for the image being created. At runtime, `dyld` uses the `runpath` when searching for dylibs whose load path begins with `@rpath/`. +LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks + +// This is a list of paths to folders to be searched by the linker for libraries used by the product. Paths are delimited by whitespace, so any paths with spaces in them need to be properly quoted. +LIBRARY_SEARCH_PATHS = $(inherited) + +// Code will load on this and later versions of macOS. Framework APIs that are unavailable in earlier versions will be weak-linked; your code should check for null function pointers or specific system versions before calling newer APIs. +MACOSX_DEPLOYMENT_TARGET = 10.10 + +// Options defined in this setting are passed to invocations of the linker. +OTHER_LDFLAGS = -ObjC + +// A string that uniquely identifies the bundle. The string should be in reverse DNS format using only alphanumeric characters (`A-Z`, `a-z`, `0-9`), the dot (`.`), and the hyphen (`-`). This value is used as the `CFBundleIdentifier` in the `Info.plist` of the built bundle. +PRODUCT_BUNDLE_IDENTIFIER_PREFIX = com.dailymotion +PRODUCT_BUNDLE_IDENTIFIER = $(PRODUCT_BUNDLE_IDENTIFIER_PREFIX).${PRODUCT_NAME:rfc1034identifier} + +// This is the basename of the product generated by the target. +PRODUCT_NAME = $(TARGET_NAME) + +// Must contain a profile name (or UUID). A missing or invalid profile will cause a build error. Use in conjunction with [DEVELOPMENT_TEAM] to fully specify provisioning profile. +PROVISIONING_PROFILE_SPECIFIER = + +// Activating this setting will cause Xcode to run the `Clang` static analysis tool on qualifying source files during every build. +RUN_CLANG_STATIC_ANALYZER = YES + +// The name or path of the base SDK being used during the build. The product will be built against the headers and libraries located inside the indicated SDK. This path will be prepended to all search paths, and will be passed through the environment to the compiler and linker. Additional SDKs can be specified in the `ADDITIONAL_SDKS` setting. +SDKROOT = macosx + +// If enabled, don't install built products even if deployment locations are active. +SKIP_INSTALL = YES + +// The list of supported platforms from which a base SDK can be used. This setting is used if the product can be built for multiple platforms using different SDKs. +SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator watchsimulator watchos appletvsimulator appletvos + +// The build system uses the selected device to set the correct value for the `UIDeviceFamily` key it adds to the target's `Info.plist` file. This also drives the --target-device flag to actool, which determines the idioms selected during catalog compilation for iOS platforms. +TARGETED_DEVICE_FAMILY = 1,2,3,4 + +// Code will load on this and later versions of tvOS. Framework APIs that are unavailable in earlier versions will be weak-linked; your code should check for null function pointers or specific system versions before calling newer APIs. +TVOS_DEPLOYMENT_TARGET = 9.0 + +// Selects the process used for version-stamping generated files. * *None:* Use no versioning system. * *Apple Generic:* Use the current project version setting. [apple-generic] +VERSIONING_SYSTEM = apple-generic + +// Code will load on this and later versions of watchOS. Framework APIs that are unavailable in earlier versions will be weak-linked; your code should check for null function pointers or specific system versions before calling newer APIs. +WATCHOS_DEPLOYMENT_TARGET = 2.0 diff --git a/Examples/SDWebImage Demo.xcodeproj/project.pbxproj b/Examples/SDWebImage Demo.xcodeproj/project.pbxproj index e3139c4f..4bc434e7 100644 --- a/Examples/SDWebImage Demo.xcodeproj/project.pbxproj +++ b/Examples/SDWebImage Demo.xcodeproj/project.pbxproj @@ -7,11 +7,9 @@ objects = { /* Begin PBXBuildFile section */ - 1DFFF782AC680AB174A297D2 /* Pods_SDWebImage_Watch_Demo_Extension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C2FAC73C40132154E469AC8 /* Pods_SDWebImage_Watch_Demo_Extension.framework */; }; 32892E311FAE898C00BE8320 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 32892E301FAE898C00BE8320 /* Assets.xcassets */; }; 32892E351FAE89FE00BE8320 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 32892E341FAE89FD00BE8320 /* LaunchScreen.storyboard */; }; 3E75A9861742DBE700DA412D /* CustomPathImages in Resources */ = {isa = PBXBuildFile; fileRef = 3E75A9851742DBE700DA412D /* CustomPathImages */; }; - 3EB94398122E15A03521242D /* Pods_SDWebImage_iOS_Demo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E1C7793F375A90B31F03087 /* Pods_SDWebImage_iOS_Demo.framework */; }; 4314D1AA1D0E1181004B36C9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4314D1A91D0E1181004B36C9 /* main.m */; }; 4314D1AD1D0E1181004B36C9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4314D1AC1D0E1181004B36C9 /* AppDelegate.m */; }; 4314D1B01D0E1182004B36C9 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4314D1AF1D0E1182004B36C9 /* ViewController.m */; }; @@ -40,9 +38,11 @@ 537612B0155AB74D005750A4 /* DetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 537612AF155AB74D005750A4 /* DetailViewController.m */; }; 537612B3155AB74D005750A4 /* MasterViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 537612B1155AB74D005750A4 /* MasterViewController.xib */; }; 537612B6155AB74D005750A4 /* DetailViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 537612B4155AB74D005750A4 /* DetailViewController.xib */; }; - A335B6482715CD923F929224 /* Pods_SDWebImage_OSX_Demo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AFF4102E3D959CBB4FA13AB0 /* Pods_SDWebImage_OSX_Demo.framework */; }; - AB731AD9445BC0E9EA4F353C /* Pods_SDWebImage_TV_Demo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92719CCA7C38F5667B582562 /* Pods_SDWebImage_TV_Demo.framework */; }; + 95616EF6906FA4C794E780E4 /* Pods_SDWebImage_OSX_Demo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1299D5267E136DCF87A1A21A /* Pods_SDWebImage_OSX_Demo.framework */; }; + AE96B96B254FB4A6A222D71E /* Pods_SDWebImage_TV_Demo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BEDA5EB5742642C924545A48 /* Pods_SDWebImage_TV_Demo.framework */; }; + CF64B1471621CF4AAEC747B7 /* Pods_SDWebImage_iOS_Demo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 225ECB6E7CB8DB707B498522 /* Pods_SDWebImage_iOS_Demo.framework */; }; DA248D44195470FD00390AB0 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 537612E3155ABA3C005750A4 /* MapKit.framework */; }; + FB25FF804FC7C7868E4F9364 /* Pods_SDWebImage_Watch_Demo_Extension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0DBF9DAE0F88B4C7B529C575 /* Pods_SDWebImage_Watch_Demo_Extension.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -128,14 +128,14 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 0A5C1B2C88218143A5BCB306 /* Pods-SDWebImage OSX Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage OSX Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo.debug.xcconfig"; sourceTree = ""; }; - 1E1C7793F375A90B31F03087 /* Pods_SDWebImage_iOS_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImage_iOS_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 1E3938BD7F1865D9C3421374 /* Pods-SDWebImage iOS Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage iOS Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo.debug.xcconfig"; sourceTree = ""; }; - 201B6D833246D81FC96576AF /* Pods_SDWebImage_Watch_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImage_Watch_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 3027DFFB4B050C9E195FC1E6 /* Pods-SDWebImage TV Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage TV Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo.release.xcconfig"; sourceTree = ""; }; + 0829378FA7103DD8649CCCF3 /* Pods-SDWebImage iOS Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage iOS Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo.release.xcconfig"; sourceTree = ""; }; + 0DBF9DAE0F88B4C7B529C575 /* Pods_SDWebImage_Watch_Demo_Extension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImage_Watch_Demo_Extension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1299D5267E136DCF87A1A21A /* Pods_SDWebImage_OSX_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImage_OSX_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 225ECB6E7CB8DB707B498522 /* Pods_SDWebImage_iOS_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImage_iOS_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 28B8C1BB2DCC32E213DA3DAD /* Pods-SDWebImage TV Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage TV Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo.release.xcconfig"; sourceTree = ""; }; + 327E1C604113A7CEC9AC02DB /* Pods-SDWebImage Watch Demo Extension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage Watch Demo Extension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension.debug.xcconfig"; sourceTree = ""; }; 32892E301FAE898C00BE8320 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 32892E341FAE89FD00BE8320 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; - 3C2FAC73C40132154E469AC8 /* Pods_SDWebImage_Watch_Demo_Extension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImage_Watch_Demo_Extension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3E75A9851742DBE700DA412D /* CustomPathImages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = CustomPathImages; sourceTree = SOURCE_ROOT; }; 4314D1A61D0E1181004B36C9 /* SDWebImage TV Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SDWebImage TV Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 4314D1A91D0E1181004B36C9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; @@ -186,13 +186,18 @@ 537612B5155AB74D005750A4 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/DetailViewController.xib; sourceTree = ""; }; 537612E3155ABA3C005750A4 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; 537612E6155ABA44005750A4 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; - 92719CCA7C38F5667B582562 /* Pods_SDWebImage_TV_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImage_TV_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9B2818BFAE3E61037805BB0A /* Pods-SDWebImage Watch Demo Extension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage Watch Demo Extension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension.debug.xcconfig"; sourceTree = ""; }; - AFF4102E3D959CBB4FA13AB0 /* Pods_SDWebImage_OSX_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImage_OSX_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C78C49F71ED2172D9252509F /* Pods-SDWebImage iOS Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage iOS Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo.release.xcconfig"; sourceTree = ""; }; - CC928213A59B58D86A2040DD /* Pods-SDWebImage TV Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage TV Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo.debug.xcconfig"; sourceTree = ""; }; - E0B6B3418BA8A3EA9217E79A /* Pods-SDWebImage Watch Demo Extension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage Watch Demo Extension.release.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension.release.xcconfig"; sourceTree = ""; }; - FF1B0E74870E1C8DD6DBF631 /* Pods-SDWebImage OSX Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage OSX Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo.release.xcconfig"; sourceTree = ""; }; + 5992BFDBF29AB5CBCAC896FB /* Pods-SDWebImage OSX Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage OSX Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo.release.xcconfig"; sourceTree = ""; }; + 5A56E15AF819F64FBF1F65A9 /* Pods-SDWebImage TV Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage TV Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo.debug.xcconfig"; sourceTree = ""; }; + 789EDF4244C66933FDF3E181 /* Pods-SDWebImage iOS Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage iOS Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo.debug.xcconfig"; sourceTree = ""; }; + 80C26B77F46D9332F328204E /* Pods-SDWebImage OSX Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage OSX Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo.debug.xcconfig"; sourceTree = ""; }; + 9A205232F437C77F45A2EBD1 /* Pods-SDWebImage Watch Demo Extension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage Watch Demo Extension.release.xcconfig"; path = "Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension.release.xcconfig"; sourceTree = ""; }; + BEDA5EB5742642C924545A48 /* Pods_SDWebImage_TV_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImage_TV_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + EA9E0C74219598B400AFB434 /* Module-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Module-Release.xcconfig"; sourceTree = ""; }; + EA9E0C75219598B400AFB434 /* App-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "App-Debug.xcconfig"; sourceTree = ""; }; + EA9E0C76219598B400AFB434 /* App-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "App-Release.xcconfig"; sourceTree = ""; }; + EA9E0C77219598B400AFB434 /* Module-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Module-Debug.xcconfig"; sourceTree = ""; }; + EA9E0C78219598B400AFB434 /* App-Shared.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "App-Shared.xcconfig"; sourceTree = ""; }; + EA9E0C79219598B400AFB434 /* Module-Shared.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Module-Shared.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -200,7 +205,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - AB731AD9445BC0E9EA4F353C /* Pods_SDWebImage_TV_Demo.framework in Frameworks */, + AE96B96B254FB4A6A222D71E /* Pods_SDWebImage_TV_Demo.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -208,7 +213,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A335B6482715CD923F929224 /* Pods_SDWebImage_OSX_Demo.framework in Frameworks */, + 95616EF6906FA4C794E780E4 /* Pods_SDWebImage_OSX_Demo.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -216,7 +221,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1DFFF782AC680AB174A297D2 /* Pods_SDWebImage_Watch_Demo_Extension.framework in Frameworks */, + FB25FF804FC7C7868E4F9364 /* Pods_SDWebImage_Watch_Demo_Extension.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -229,7 +234,7 @@ 5376129A155AB74D005750A4 /* UIKit.framework in Frameworks */, 5376129C155AB74D005750A4 /* Foundation.framework in Frameworks */, 5376129E155AB74D005750A4 /* CoreGraphics.framework in Frameworks */, - 3EB94398122E15A03521242D /* Pods_SDWebImage_iOS_Demo.framework in Frameworks */, + CF64B1471621CF4AAEC747B7 /* Pods_SDWebImage_iOS_Demo.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -326,6 +331,7 @@ 5376128A155AB74D005750A4 = { isa = PBXGroup; children = ( + EA9E0C73219598B400AFB434 /* Configs */, 5376129F155AB74D005750A4 /* SDWebImage Demo */, 43A629D01D0DFD000089D7DD /* SDWebImage OSX Demo */, 43A629EF1D0E07600089D7DD /* SDWebImage Watch Demo */, @@ -333,7 +339,7 @@ 4314D1A71D0E1181004B36C9 /* SDWebImage TV Demo */, 53761298155AB74D005750A4 /* Frameworks */, 53761296155AB74D005750A4 /* Products */, - C5D3D7AE3B6CBC7C43AE7833 /* Pods */, + 75D6E1708C75E4AC2FA214EC /* Pods */, ); sourceTree = ""; }; @@ -357,11 +363,10 @@ 53761299155AB74D005750A4 /* UIKit.framework */, 5376129B155AB74D005750A4 /* Foundation.framework */, 5376129D155AB74D005750A4 /* CoreGraphics.framework */, - 1E1C7793F375A90B31F03087 /* Pods_SDWebImage_iOS_Demo.framework */, - AFF4102E3D959CBB4FA13AB0 /* Pods_SDWebImage_OSX_Demo.framework */, - 201B6D833246D81FC96576AF /* Pods_SDWebImage_Watch_Demo.framework */, - 92719CCA7C38F5667B582562 /* Pods_SDWebImage_TV_Demo.framework */, - 3C2FAC73C40132154E469AC8 /* Pods_SDWebImage_Watch_Demo_Extension.framework */, + 1299D5267E136DCF87A1A21A /* Pods_SDWebImage_OSX_Demo.framework */, + BEDA5EB5742642C924545A48 /* Pods_SDWebImage_TV_Demo.framework */, + 0DBF9DAE0F88B4C7B529C575 /* Pods_SDWebImage_Watch_Demo_Extension.framework */, + 225ECB6E7CB8DB707B498522 /* Pods_SDWebImage_iOS_Demo.framework */, ); name = Frameworks; sourceTree = ""; @@ -395,21 +400,35 @@ name = "Supporting Files"; sourceTree = ""; }; - C5D3D7AE3B6CBC7C43AE7833 /* Pods */ = { + 75D6E1708C75E4AC2FA214EC /* Pods */ = { isa = PBXGroup; children = ( - 1E3938BD7F1865D9C3421374 /* Pods-SDWebImage iOS Demo.debug.xcconfig */, - C78C49F71ED2172D9252509F /* Pods-SDWebImage iOS Demo.release.xcconfig */, - 0A5C1B2C88218143A5BCB306 /* Pods-SDWebImage OSX Demo.debug.xcconfig */, - FF1B0E74870E1C8DD6DBF631 /* Pods-SDWebImage OSX Demo.release.xcconfig */, - CC928213A59B58D86A2040DD /* Pods-SDWebImage TV Demo.debug.xcconfig */, - 3027DFFB4B050C9E195FC1E6 /* Pods-SDWebImage TV Demo.release.xcconfig */, - 9B2818BFAE3E61037805BB0A /* Pods-SDWebImage Watch Demo Extension.debug.xcconfig */, - E0B6B3418BA8A3EA9217E79A /* Pods-SDWebImage Watch Demo Extension.release.xcconfig */, + 80C26B77F46D9332F328204E /* Pods-SDWebImage OSX Demo.debug.xcconfig */, + 5992BFDBF29AB5CBCAC896FB /* Pods-SDWebImage OSX Demo.release.xcconfig */, + 5A56E15AF819F64FBF1F65A9 /* Pods-SDWebImage TV Demo.debug.xcconfig */, + 28B8C1BB2DCC32E213DA3DAD /* Pods-SDWebImage TV Demo.release.xcconfig */, + 327E1C604113A7CEC9AC02DB /* Pods-SDWebImage Watch Demo Extension.debug.xcconfig */, + 9A205232F437C77F45A2EBD1 /* Pods-SDWebImage Watch Demo Extension.release.xcconfig */, + 789EDF4244C66933FDF3E181 /* Pods-SDWebImage iOS Demo.debug.xcconfig */, + 0829378FA7103DD8649CCCF3 /* Pods-SDWebImage iOS Demo.release.xcconfig */, ); name = Pods; sourceTree = ""; }; + EA9E0C73219598B400AFB434 /* Configs */ = { + isa = PBXGroup; + children = ( + EA9E0C75219598B400AFB434 /* App-Debug.xcconfig */, + EA9E0C76219598B400AFB434 /* App-Release.xcconfig */, + EA9E0C78219598B400AFB434 /* App-Shared.xcconfig */, + EA9E0C77219598B400AFB434 /* Module-Debug.xcconfig */, + EA9E0C74219598B400AFB434 /* Module-Release.xcconfig */, + EA9E0C79219598B400AFB434 /* Module-Shared.xcconfig */, + ); + name = Configs; + path = ../Configs; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -417,12 +436,12 @@ isa = PBXNativeTarget; buildConfigurationList = 4314D1B71D0E1182004B36C9 /* Build configuration list for PBXNativeTarget "SDWebImage TV Demo" */; buildPhases = ( - C1A2E0ED98B257BB14D9BD35 /* [CP] Check Pods Manifest.lock */, + B58F48B09636942C94CB9C9F /* [CP] Check Pods Manifest.lock */, 4314D1A21D0E1181004B36C9 /* Sources */, 4314D1A31D0E1181004B36C9 /* Frameworks */, 4314D1A41D0E1181004B36C9 /* Resources */, 327E2DE01FAF0D8000EF52C2 /* Embed Frameworks */, - 30CA4D7A6B97CD11FB023FCD /* [CP] Embed Pods Frameworks */, + FB94446B4DACAF8F385EB57C /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -437,12 +456,12 @@ isa = PBXNativeTarget; buildConfigurationList = 43A629E81D0DFD000089D7DD /* Build configuration list for PBXNativeTarget "SDWebImage OSX Demo" */; buildPhases = ( - E6792144F5EDB318B9B3E808 /* [CP] Check Pods Manifest.lock */, + A50199B809E737E017D7DF1C /* [CP] Check Pods Manifest.lock */, 43A629CB1D0DFD000089D7DD /* Sources */, 43A629CC1D0DFD000089D7DD /* Frameworks */, 43A629CD1D0DFD000089D7DD /* Resources */, 327E2DD61FAF0D7000EF52C2 /* Embed Frameworks */, - D3795F96D778EA0D160C99E0 /* [CP] Embed Pods Frameworks */, + 597F887D0D1A778333E020BA /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -475,12 +494,12 @@ isa = PBXNativeTarget; buildConfigurationList = 43A62A101D0E07600089D7DD /* Build configuration list for PBXNativeTarget "SDWebImage Watch Demo Extension" */; buildPhases = ( - 845ACCC963F0540C3714E294 /* [CP] Check Pods Manifest.lock */, + B65A37AE44E8F76BEB656502 /* [CP] Check Pods Manifest.lock */, 43A629F61D0E07600089D7DD /* Sources */, 43A629F71D0E07600089D7DD /* Frameworks */, 43A629F81D0E07600089D7DD /* Resources */, 327E2DDB1FAF0D7A00EF52C2 /* Embed Frameworks */, - D108C032EF2001F3466266B0 /* [CP] Embed Pods Frameworks */, + 85F5B7F46D00990FBEBF0377 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -495,13 +514,13 @@ isa = PBXNativeTarget; buildConfigurationList = 537612B9155AB74D005750A4 /* Build configuration list for PBXNativeTarget "SDWebImage iOS Demo" */; buildPhases = ( - C4617CE0275D471FCDB0F0BF /* [CP] Check Pods Manifest.lock */, + FA507C7A3DC5CD9451511EB7 /* [CP] Check Pods Manifest.lock */, 53761291155AB74D005750A4 /* Sources */, 53761292155AB74D005750A4 /* Frameworks */, 53761293155AB74D005750A4 /* Resources */, 43A62A171D0E07600089D7DD /* Embed Watch Content */, 327E2DD11FAF0D6A00EF52C2 /* Embed Frameworks */, - AEB35AD7EBE9525CAF4048E9 /* [CP] Embed Pods Frameworks */, + 8425DD76050A8A49F8DAF736 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -609,130 +628,12 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 30CA4D7A6B97CD11FB023FCD /* [CP] Embed Pods Frameworks */ = { + 597F887D0D1A778333E020BA /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/SDWebImage-tvOS/SDWebImage.framework", - "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder-tvOS/SDWebImageWebPCoder.framework", - "${BUILT_PRODUCTS_DIR}/libwebp-tvOS/libwebp.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 845ACCC963F0540C3714E294 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-SDWebImage Watch Demo Extension-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - AEB35AD7EBE9525CAF4048E9 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/SDWebImage-iOS/SDWebImage.framework", - "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder-iOS/SDWebImageWebPCoder.framework", - "${BUILT_PRODUCTS_DIR}/libwebp-iOS/libwebp.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - C1A2E0ED98B257BB14D9BD35 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-SDWebImage TV Demo-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - C4617CE0275D471FCDB0F0BF /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-SDWebImage iOS Demo-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - D108C032EF2001F3466266B0 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/SDWebImage-watchOS/SDWebImage.framework", - "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder-watchOS/SDWebImageWebPCoder.framework", - "${BUILT_PRODUCTS_DIR}/libwebp-watchOS/libwebp.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - D3795F96D778EA0D160C99E0 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( + inputFileListPaths = ( ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo-frameworks.sh", @@ -741,6 +642,8 @@ "${BUILT_PRODUCTS_DIR}/libwebp-macOS/libwebp.framework", ); name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + ); outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", @@ -751,16 +654,72 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - E6792144F5EDB318B9B3E808 /* [CP] Check Pods Manifest.lock */ = { + 8425DD76050A8A49F8DAF736 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/SDWebImage-iOS/SDWebImage.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder-iOS/SDWebImageWebPCoder.framework", + "${BUILT_PRODUCTS_DIR}/libwebp-iOS/libwebp.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + ); + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 85F5B7F46D00990FBEBF0377 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/SDWebImage-watchOS/SDWebImage.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder-watchOS/SDWebImageWebPCoder.framework", + "${BUILT_PRODUCTS_DIR}/libwebp-watchOS/libwebp.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + ); + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + A50199B809E737E017D7DF1C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-SDWebImage OSX Demo-checkManifestLockResult.txt", ); @@ -769,6 +728,98 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + B58F48B09636942C94CB9C9F /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-SDWebImage TV Demo-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + B65A37AE44E8F76BEB656502 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-SDWebImage Watch Demo Extension-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + FA507C7A3DC5CD9451511EB7 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-SDWebImage iOS Demo-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + FB94446B4DACAF8F385EB57C /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/SDWebImage-tvOS/SDWebImage.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder-tvOS/SDWebImageWebPCoder.framework", + "${BUILT_PRODUCTS_DIR}/libwebp-tvOS/libwebp.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + ); + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -874,466 +925,149 @@ /* Begin XCBuildConfiguration section */ 4314D1B81D0E1182004B36C9 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = CC928213A59B58D86A2040DD /* Pods-SDWebImage TV Demo.debug.xcconfig */; + baseConfigurationReference = 5A56E15AF819F64FBF1F65A9 /* Pods-SDWebImage TV Demo.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = "SDWebImage TV Demo/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.SDWebImage-TV-Demo"; - PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; + SUPPORTED_PLATFORMS = "appletvsimulator appletvos"; TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; }; 4314D1B91D0E1182004B36C9 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 3027DFFB4B050C9E195FC1E6 /* Pods-SDWebImage TV Demo.release.xcconfig */; + baseConfigurationReference = 28B8C1BB2DCC32E213DA3DAD /* Pods-SDWebImage TV Demo.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = "SDWebImage TV Demo/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.SDWebImage-TV-Demo"; - PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; + SUPPORTED_PLATFORMS = "appletvsimulator appletvos"; TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Release; }; 43A629E01D0DFD000089D7DD /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 0A5C1B2C88218143A5BCB306 /* Pods-SDWebImage OSX Demo.debug.xcconfig */; + baseConfigurationReference = 80C26B77F46D9332F328204E /* Pods-SDWebImage OSX Demo.debug.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = "SDWebImage OSX Demo/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.SDWebImage-OSX-Demo"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; + SDKROOT = ""; + SUPPORTED_PLATFORMS = macosx; + TARGETED_DEVICE_FAMILY = ""; }; name = Debug; }; 43A629E11D0DFD000089D7DD /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = FF1B0E74870E1C8DD6DBF631 /* Pods-SDWebImage OSX Demo.release.xcconfig */; + baseConfigurationReference = 5992BFDBF29AB5CBCAC896FB /* Pods-SDWebImage OSX Demo.release.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = "SDWebImage OSX Demo/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.SDWebImage-OSX-Demo"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; + SDKROOT = ""; + SUPPORTED_PLATFORMS = macosx; + TARGETED_DEVICE_FAMILY = ""; }; name = Release; }; 43A62A111D0E07600089D7DD /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9B2818BFAE3E61037805BB0A /* Pods-SDWebImage Watch Demo Extension.debug.xcconfig */; + baseConfigurationReference = 327E1C604113A7CEC9AC02DB /* Pods-SDWebImage Watch Demo Extension.debug.xcconfig */; buildSettings = { - APPLICATION_EXTENSION_API_ONLY = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = ""; INFOPLIST_FILE = "SDWebImage Watch Demo Extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.SDWebImage-iOS-Demo.watchkitapp.watchkitextension"; - PRODUCT_NAME = "${TARGET_NAME}"; SDKROOT = watchos; - SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "watchsimulator watchos"; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Debug; }; 43A62A121D0E07600089D7DD /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = E0B6B3418BA8A3EA9217E79A /* Pods-SDWebImage Watch Demo Extension.release.xcconfig */; + baseConfigurationReference = 9A205232F437C77F45A2EBD1 /* Pods-SDWebImage Watch Demo Extension.release.xcconfig */; buildSettings = { - APPLICATION_EXTENSION_API_ONLY = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = ""; INFOPLIST_FILE = "SDWebImage Watch Demo Extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.SDWebImage-iOS-Demo.watchkitapp.watchkitextension"; - PRODUCT_NAME = "${TARGET_NAME}"; SDKROOT = watchos; - SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "watchsimulator watchos"; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Release; }; 43A62A151D0E07600089D7DD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; IBSC_MODULE = SDWebImage_Watch_Demo_Extension; INFOPLIST_FILE = "SDWebImage Watch Demo/Info.plist"; - MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.SDWebImage-iOS-Demo.watchkitapp"; - PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; - SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "watchsimulator watchos"; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Debug; }; 43A62A161D0E07600089D7DD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; IBSC_MODULE = SDWebImage_Watch_Demo_Extension; INFOPLIST_FILE = "SDWebImage Watch Demo/Info.plist"; - MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.SDWebImage-iOS-Demo.watchkitapp"; - PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; - SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "watchsimulator watchos"; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Release; }; 537612B7155AB74D005750A4 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = EA9E0C75219598B400AFB434 /* App-Debug.xcconfig */; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = "compiler-default"; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_VERSION = ""; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - ONLY_ACTIVE_ARCH = YES; }; name = Debug; }; 537612B8155AB74D005750A4 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = EA9E0C76219598B400AFB434 /* App-Release.xcconfig */; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = YES; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = "compiler-default"; - GCC_NO_COMMON_BLOCKS = YES; - GCC_VERSION = ""; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; - VALIDATE_PRODUCT = YES; }; name = Release; }; 537612BA155AB74D005750A4 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 1E3938BD7F1865D9C3421374 /* Pods-SDWebImage iOS Demo.debug.xcconfig */; + baseConfigurationReference = 789EDF4244C66933FDF3E181 /* Pods-SDWebImage iOS Demo.debug.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)\"", - ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "SDWebImage Demo/SDWebImage Demo-Prefix.pch"; - HEADER_SEARCH_PATHS = ( - "\"$(OBJROOT)/UninstalledProducts/include\"", - "\"$(TARGET_BUILD_DIR)/usr/local/lib/include\"", - ); INFOPLIST_FILE = "SDWebImage Demo/SDWebImage Demo-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.${PRODUCT_NAME:rfc1034identifier}"; - PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; - WRAPPER_EXTENSION = app; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 537612BB155AB74D005750A4 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = C78C49F71ED2172D9252509F /* Pods-SDWebImage iOS Demo.release.xcconfig */; + baseConfigurationReference = 0829378FA7103DD8649CCCF3 /* Pods-SDWebImage iOS Demo.release.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)\"", - ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "SDWebImage Demo/SDWebImage Demo-Prefix.pch"; - HEADER_SEARCH_PATHS = ( - "\"$(OBJROOT)/UninstalledProducts/include\"", - "\"$(TARGET_BUILD_DIR)/usr/local/lib/include\"", - ); INFOPLIST_FILE = "SDWebImage Demo/SDWebImage Demo-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.${PRODUCT_NAME:rfc1034identifier}"; - PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; - WRAPPER_EXTENSION = app; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; diff --git a/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX Demo.xcscheme b/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX Demo.xcscheme index 29c6338d..eb02bf27 100644 --- a/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX Demo.xcscheme +++ b/Examples/SDWebImage Demo.xcodeproj/xcshareddata/xcschemes/SDWebImage OSX Demo.xcscheme @@ -1,6 +1,6 @@ @@ -46,7 +46,7 @@ diff --git a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage.xcscheme b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage.xcscheme index c5e94640..0593868e 100644 --- a/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage.xcscheme +++ b/SDWebImage.xcodeproj/xcshareddata/xcschemes/SDWebImage.xcscheme @@ -1,6 +1,6 @@ /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3742A83C8569610075078F4D /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Tests Mac-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 910EDDDEAAC8A165A883AD8F /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-Tests Mac/Pods-Tests Mac-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Expecta-macOS/Expecta.framework", @@ -363,6 +424,8 @@ "${BUILT_PRODUCTS_DIR}/SDWebImage-macOS/SDWebImage.framework", ); name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + ); outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Expecta.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KVOController.framework", @@ -373,46 +436,12 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests Mac/Pods-Tests Mac-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 09522B7196293172D6408744 /* [CP] Check Pods Manifest.lock */ = { + A07943B19E185DC24535F340 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Tests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - C584EBF185E2BBD234CD3350 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Tests Mac-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - C86216497B5A0BA9501E2C07 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( + inputFileListPaths = ( ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-frameworks.sh", @@ -421,6 +450,8 @@ "${BUILT_PRODUCTS_DIR}/SDWebImage-iOS/SDWebImage.framework", ); name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + ); outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Expecta.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KVOController.framework", @@ -496,228 +527,71 @@ /* Begin XCBuildConfiguration section */ 32B99E97203B2DF90017FD66 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 3B82F4E5C79656CB9C5667F6 /* Pods-Tests Mac.debug.xcconfig */; + baseConfigurationReference = BC6C6328775701B5AAEEF4FF /* Pods-Tests Mac.debug.xcconfig */; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Manual; - COMBINE_HIDPI_IMAGES = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INFOPLIST_FILE = "Tests Mac/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.12; - MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.Tests-Mac"; - PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; + SUPPORTED_PLATFORMS = macosx; + TARGETED_DEVICE_FAMILY = ""; }; name = Debug; }; 32B99E98203B2DF90017FD66 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5420AE085F25F0E156B00284 /* Pods-Tests Mac.release.xcconfig */; + baseConfigurationReference = 4835C04148C737D0FC50EF87 /* Pods-Tests Mac.release.xcconfig */; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Manual; - COMBINE_HIDPI_IMAGES = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; - ENABLE_NS_ASSERTIONS = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INFOPLIST_FILE = "Tests Mac/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.12; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = "com.dailymotion.Tests-Mac"; - PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; + SUPPORTED_PLATFORMS = macosx; + TARGETED_DEVICE_FAMILY = ""; }; name = Release; }; DA248D4A1954721A00390AB0 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = EADD19EC219915E300804BB0 /* Module-Debug.xcconfig */; buildSettings = { - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.10; - ONLY_ACTIVE_ARCH = YES; }; name = Debug; }; DA248D4B1954721A00390AB0 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = EADD19E9219915E300804BB0 /* Module-Release.xcconfig */; buildSettings = { - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.10; }; name = Release; }; DA248D65195472AA00390AB0 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 700B00151041D7EE118B1ABD /* Pods-Tests.debug.xcconfig */; + baseConfigurationReference = 0AD1DD30CCB1B928CFA9740B /* Pods-Tests.debug.xcconfig */; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = "Tests/Tests-Info.plist"; - ONLY_ACTIVE_ARCH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.SDWebImage.${PRODUCT_NAME:rfc1034identifier}"; - PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; - WRAPPER_EXTENSION = xctest; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; DA248D66195472AA00390AB0 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = A0085854E7D88C98F2F6C9FC /* Pods-Tests.release.xcconfig */; + baseConfigurationReference = 6700DBD9C45B00AB5F77472A /* Pods-Tests.release.xcconfig */; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = YES; - ENABLE_NS_ASSERTIONS = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch"; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = "Tests/Tests-Info.plist"; - PRODUCT_BUNDLE_IDENTIFIER = "com.SDWebImage.${PRODUCT_NAME:rfc1034identifier}"; - PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - WRAPPER_EXTENSION = xctest; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; diff --git a/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests Mac.xcscheme b/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests Mac.xcscheme index f051ab77..ad9db09a 100644 --- a/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests Mac.xcscheme +++ b/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests Mac.xcscheme @@ -1,6 +1,6 @@ Date: Sun, 11 Nov 2018 21:10:50 -0600 Subject: [PATCH 282/361] Fixes (use xcode10 image, no need for inputFileListPaths or outputFileListPaths) --- .travis.yml | 4 +-- .../SDWebImage Demo.xcodeproj/project.pbxproj | 32 ------------------- .../project.pbxproj | 18 ++--------- 3 files changed, 4 insertions(+), 50 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6f536f4f..2527a7ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: objective-c -osx_image: xcode9.4 +osx_image: xcode10 env: global: @@ -13,7 +13,7 @@ notifications: before_install: - env - locale - - gem install cocoapods --no-rdoc --no-ri --no-document --quiet + - gem install cocoapods --pre --no-rdoc --no-ri --no-document --quiet - gem install xcpretty --no-rdoc --no-ri --no-document --quiet - pod --version - pod setup --silent > /dev/null diff --git a/Examples/SDWebImage Demo.xcodeproj/project.pbxproj b/Examples/SDWebImage Demo.xcodeproj/project.pbxproj index 4bc434e7..977ec945 100644 --- a/Examples/SDWebImage Demo.xcodeproj/project.pbxproj +++ b/Examples/SDWebImage Demo.xcodeproj/project.pbxproj @@ -633,8 +633,6 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo-frameworks.sh", "${BUILT_PRODUCTS_DIR}/SDWebImage-macOS/SDWebImage.framework", @@ -642,8 +640,6 @@ "${BUILT_PRODUCTS_DIR}/libwebp-macOS/libwebp.framework", ); name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - ); outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", @@ -659,8 +655,6 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo-frameworks.sh", "${BUILT_PRODUCTS_DIR}/SDWebImage-iOS/SDWebImage.framework", @@ -668,8 +662,6 @@ "${BUILT_PRODUCTS_DIR}/libwebp-iOS/libwebp.framework", ); name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - ); outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", @@ -685,8 +677,6 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension-frameworks.sh", "${BUILT_PRODUCTS_DIR}/SDWebImage-watchOS/SDWebImage.framework", @@ -694,8 +684,6 @@ "${BUILT_PRODUCTS_DIR}/libwebp-watchOS/libwebp.framework", ); name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - ); outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", @@ -711,15 +699,11 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-SDWebImage OSX Demo-checkManifestLockResult.txt", ); @@ -733,15 +717,11 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-SDWebImage TV Demo-checkManifestLockResult.txt", ); @@ -755,15 +735,11 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-SDWebImage Watch Demo Extension-checkManifestLockResult.txt", ); @@ -777,15 +753,11 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-SDWebImage iOS Demo-checkManifestLockResult.txt", ); @@ -799,8 +771,6 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo-frameworks.sh", "${BUILT_PRODUCTS_DIR}/SDWebImage-tvOS/SDWebImage.framework", @@ -808,8 +778,6 @@ "${BUILT_PRODUCTS_DIR}/libwebp-tvOS/libwebp.framework", ); name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - ); outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 413154dd..fb70541b 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -371,15 +371,11 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-Tests-checkManifestLockResult.txt", ); @@ -393,15 +389,11 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-Tests Mac-checkManifestLockResult.txt", ); @@ -415,8 +407,6 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-Tests Mac/Pods-Tests Mac-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Expecta-macOS/Expecta.framework", @@ -424,8 +414,6 @@ "${BUILT_PRODUCTS_DIR}/SDWebImage-macOS/SDWebImage.framework", ); name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - ); outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Expecta.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KVOController.framework", @@ -441,8 +429,6 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Expecta-iOS/Expecta.framework", @@ -450,8 +436,6 @@ "${BUILT_PRODUCTS_DIR}/SDWebImage-iOS/SDWebImage.framework", ); name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - ); outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Expecta.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KVOController.framework", @@ -532,6 +516,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; + ENABLE_BITCODE = NO; INFOPLIST_FILE = "Tests Mac/Info.plist"; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; @@ -547,6 +532,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; + ENABLE_BITCODE = NO; INFOPLIST_FILE = "Tests Mac/Info.plist"; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; From f7a37ce72c105405c77f0e9cc9f2494c30e901e9 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Sun, 11 Nov 2018 21:29:13 -0600 Subject: [PATCH 283/361] iPhone 8 sim doesn't exist on Xcode10 (when targetting watch simulator). Use iPhone XS --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2527a7ec..9fc5c56e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,15 +44,15 @@ script: - echo Build the Demo apps - pod install --project-directory=Examples - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX Demo' -sdk macosx -configuration Debug | xcpretty -c - - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 8' | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone XS' | xcpretty -c - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage TV Demo' -sdk appletvsimulator -configuration Debug | xcpretty -c - - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone 8' | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone XS' | xcpretty -c - mkdir DerivedData - echo Run the tests - pod install --project-directory=Tests - - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 8' -configuration Debug | xcpretty -c + - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone XS' -configuration Debug | xcpretty -c - mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/iOS - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests Mac' -sdk macosx -destination 'platform=OS X,arch=x86_64' -configuration Debug | xcpretty -c - mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/macOS From d89b735708e265cf3879f5afb1e0c15c40e8861c Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Sun, 11 Nov 2018 21:50:44 -0600 Subject: [PATCH 284/361] Fixed some warnings in the tests --- Tests/Tests/SDImageTransformerTests.m | 1 - Tests/Tests/SDWebImageDownloaderTests.m | 4 ++-- Tests/Tests/SDWebImageManagerTests.m | 18 +++++++++--------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Tests/Tests/SDImageTransformerTests.m b/Tests/Tests/SDImageTransformerTests.m index 105be68e..bcbfd7b8 100644 --- a/Tests/Tests/SDImageTransformerTests.m +++ b/Tests/Tests/SDImageTransformerTests.m @@ -72,7 +72,6 @@ rotatedImage = [self.testImage sd_rotatedImageWithAngle:angle fitSize:YES]; CGSize rotatedSize = CGSizeMake(floor(300 * 1.414), floor(300 * 1.414)); // 45º, square length * sqrt(2) expect(CGSizeEqualToSize(rotatedImage.size, rotatedSize)).beTruthy(); - rotatedImage = [self.testImage sd_rotatedImageWithAngle:angle fitSize:NO]; } - (void)test05UIImageTransformFlip { diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index 9c328344..fce1d25f 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -181,9 +181,9 @@ - (void)test12ThatWeCanUseAnotherSessionForEachDownloadOperation { XCTestExpectation *expectation = [self expectationWithDescription:@"Owned session"]; - NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; + NSURL *url = [NSURL URLWithString:kTestJPEGURL]; - NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:imageURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15]; + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15]; request.HTTPShouldUsePipelining = YES; request.allHTTPHeaderFields = @{@"Accept": @"image/*;q=0.8"}; diff --git a/Tests/Tests/SDWebImageManagerTests.m b/Tests/Tests/SDWebImageManagerTests.m index 380a019d..2e6d0f3b 100644 --- a/Tests/Tests/SDWebImageManagerTests.m +++ b/Tests/Tests/SDWebImageManagerTests.m @@ -66,8 +66,8 @@ // need a bigger image here, that is why we don't use kTestJPEGURL // if the image is too small, it will get downloaded before we can cancel :) - NSURL *imageURL = [NSURL URLWithString:@"https://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"]; - [[SDWebImageManager sharedManager] loadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + NSURL *url = [NSURL URLWithString:@"https://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"]; + [[SDWebImageManager sharedManager] loadImageWithURL:url options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { XCTFail(@"Should not get here"); }]; @@ -111,14 +111,14 @@ - (void)test08ThatImageTransformerWork { XCTestExpectation *expectation = [self expectationWithDescription:@"Image transformer work"]; - NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; + NSURL *url = [NSURL URLWithString:kTestJPEGURL]; SDWebImageTestTransformer *transformer = [[SDWebImageTestTransformer alloc] init]; transformer.testImage = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]]; SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:[SDImageCache sharedImageCache] loader:[SDWebImageDownloader sharedDownloader]]; manager.transformer = transformer; [[SDImageCache sharedImageCache] removeImageForKey:kTestJPEGURL withCompletion:^{ - [manager loadImageWithURL:imageURL options:SDWebImageTransformAnimatedImage progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + [manager loadImageWithURL:url options:SDWebImageTransformAnimatedImage progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { expect(image).equal(transformer.testImage); [expectation fulfill]; }]; @@ -129,10 +129,10 @@ - (void)test09ThatCacheKeyFilterWork { XCTestExpectation *expectation = [self expectationWithDescription:@"Cache key filter work"]; - NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; + NSURL *url = [NSURL URLWithString:kTestJPEGURL]; NSString *cacheKey = @"kTestJPEGURL"; - SDWebImageCacheKeyFilter *cacheKeyFilter = [SDWebImageCacheKeyFilter cacheKeyFilterWithBlock:^NSString * _Nullable(NSURL * _Nonnull url) { + SDWebImageCacheKeyFilter *cacheKeyFilter = [SDWebImageCacheKeyFilter cacheKeyFilterWithBlock:^NSString * _Nullable(NSURL * _Nonnull imageURL) { if ([url isEqual:imageURL]) { return cacheKey; } else { @@ -143,7 +143,7 @@ SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:[SDImageCache sharedImageCache] loader:[SDWebImageDownloader sharedDownloader]]; manager.cacheKeyFilter = cacheKeyFilter; // Check download and retrieve custom cache key - [manager loadImageWithURL:imageURL options:0 context:@{SDWebImageContextStoreCacheType : @(SDImageCacheTypeMemory)} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + [manager loadImageWithURL:url options:0 context:@{SDWebImageContextStoreCacheType : @(SDImageCacheTypeMemory)} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { expect(cacheType).equal(SDImageCacheTypeNone); // Check memory cache exist @@ -159,7 +159,7 @@ - (void)test10ThatCacheSerializerWork { XCTestExpectation *expectation = [self expectationWithDescription:@"Cache serializer work"]; - NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; + NSURL *url = [NSURL URLWithString:kTestJPEGURL]; __block NSData *imageData; SDWebImageCacheSerializer *cacheSerializer = [SDWebImageCacheSerializer cacheSerializerWithBlock:^NSData * _Nullable(UIImage * _Nonnull image, NSData * _Nullable data, NSURL * _Nullable imageURL) { @@ -171,7 +171,7 @@ manager.cacheSerializer = cacheSerializer; // Check download and store custom disk data [[SDImageCache sharedImageCache] removeImageForKey:kTestJPEGURL withCompletion:^{ - [manager loadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + [manager loadImageWithURL:url options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { // Dispatch to let store disk finish dispatch_after(dispatch_time(DISPATCH_TIME_NOW, kMinDelayNanosecond), dispatch_get_main_queue(), ^{ NSData *diskImageData = [[SDImageCache sharedImageCache] diskImageDataForKey:kTestJPEGURL]; From 8c7764e122d32d199a6b40db26bb62e4ad1e9688 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 15 Nov 2018 21:13:27 +0800 Subject: [PATCH 285/361] Fix comments in code --- SDWebImage/SDImageCoder.h | 2 +- SDWebImage/SDImageCodersManager.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SDWebImage/SDImageCoder.h b/SDWebImage/SDImageCoder.h index ff28a5cd..3b2049e5 100644 --- a/SDWebImage/SDImageCoder.h +++ b/SDWebImage/SDImageCoder.h @@ -167,7 +167,7 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderWebImageContext; /** Total animated frame count. - It the frame count is less than 1, then the methods below will be ignored. + If the frame count is less than 1, then the methods below will be ignored. @return Total animated frame count. */ diff --git a/SDWebImage/SDImageCodersManager.h b/SDWebImage/SDImageCodersManager.h index 0d300786..e4276464 100644 --- a/SDWebImage/SDImageCodersManager.h +++ b/SDWebImage/SDImageCodersManager.h @@ -20,7 +20,7 @@ - by default we internally set coders = `IOCoder`, `GIFCoder` - calling `coders` will return `@[IOCoder, GIFCoder]` - call `[addCoder:[MyCrazyCoder new]]` - - calling `coders` now returns `@[MyCrazyCoder, IOCoder, GIFCoder]` + - calling `coders` now returns `@[IOCoder, GIFCoder, MyCrazyCoder]` Coders ------ @@ -29,7 +29,7 @@ Those methods are called on each coder in the array (using the priority order) until one of them returns YES. That means that coder can decode that data / encode to that format */ -@interface SDImageCodersManager : NSObject +@interface SDImageCodersManager : NSObject /** Returns the global shared coders manager instance. From 9dacf99738b02245ffe2e26b92010fded5cfae13 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 15 Nov 2018 21:32:05 +0800 Subject: [PATCH 286/361] update --- SDWebImage/UIImageView+WebCache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/UIImageView+WebCache.h b/SDWebImage/UIImageView+WebCache.h index f84217e0..844081f8 100644 --- a/SDWebImage/UIImageView+WebCache.h +++ b/SDWebImage/UIImageView+WebCache.h @@ -30,7 +30,7 @@ cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier]; } - // Here we use the provided sd_setImageWithURL: method to load the web image + // Here we use the provided sd_setImageWithURL:placeholderImage: method to load the web image // Ensure you use a placeholder image otherwise cells will be initialized with no image [cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://example.com/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder"]]; From b0c84e8aec1ef450633bd9f1aa5b654c3e2003af Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 8 Dec 2018 12:55:26 +0800 Subject: [PATCH 287/361] Fix that macOS does not support bitcode, this cause build issue on Legacy Build System --- Configs/Module-Shared.xcconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Configs/Module-Shared.xcconfig b/Configs/Module-Shared.xcconfig index 7b427751..9bacfd5d 100644 --- a/Configs/Module-Shared.xcconfig +++ b/Configs/Module-Shared.xcconfig @@ -111,6 +111,8 @@ DYLIB_INSTALL_NAME_BASE = @rpath // Activating this setting indicates that the target or project should generate bitcode during compilation for platforms and architectures that support it. For Archive builds, bitcode will be generated in the linked binary for submission to the App Store. For other builds, the compiler and linker will check whether the code complies with the requirements for bitcode generation, but will not generate actual bitcode. ENABLE_BITCODE = YES +// Mac OS X does not support bitcode. +ENABLE_BITCODE[sdk=macosx*] = NO // Controls whether `objc_msgSend` calls must be cast to the appropriate function pointer type before being called. ENABLE_STRICT_OBJC_MSGSEND = YES From b68730bedfe16fa56ed5f6fe8a1d6ee6da51dbc7 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 17 Nov 2018 13:09:11 +0800 Subject: [PATCH 288/361] Use the more intuitive and suitable cache path for SDImageCache. Defaults now to `~Library/Caches/com.hackemist.SDImageCache/default/`, namespace controls the sub-directory name. Remove the namespacePrefix property because now it's not follows what it says --- SDWebImage/SDImageCache.h | 8 +++++--- SDWebImage/SDImageCache.m | 27 ++++++++++++--------------- SDWebImage/SDImageCacheConfig.h | 6 ------ SDWebImage/SDImageCacheConfig.m | 2 -- Tests/Tests/SDImageCacheTests.m | 14 ++++++-------- 5 files changed, 23 insertions(+), 34 deletions(-) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index bf8dfc6d..558ead6a 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -87,23 +87,25 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns; /** - * Init a new cache store with a specific namespace and directory + * Init a new cache store with a specific namespace and directory. + * If you don't provide the disk cache directory, we will use the User Cache directory with prefix (~/Library/Caches/com.hackemist.SDImageCache/). * * @param ns The namespace to use for this cache store * @param directory Directory to cache disk images in */ - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns - diskCacheDirectory:(nonnull NSString *)directory; + diskCacheDirectory:(nullable NSString *)directory; /** * Init a new cache store with a specific namespace, directory and file manager + * The final disk cache directory should looks like ($directory/$namespace). And the default config of shared cache, should result in (~/Library/Caches/com.hackemist.SDImageCache/default/) * * @param ns The namespace to use for this cache store * @param directory Directory to cache disk images in * @param config The cache config to be used to create the cache. You can provide custom memory cache or disk cache class in the cache config */ - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns - diskCacheDirectory:(nonnull NSString *)directory + diskCacheDirectory:(nullable NSString *)directory config:(nullable SDImageCacheConfig *)config NS_DESIGNATED_INITIALIZER; #pragma mark - Cache paths diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 6a093511..db5a02ea 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -45,24 +45,19 @@ } - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns { - NSString *path = [self makeDiskCachePath:ns]; - return [self initWithNamespace:ns diskCacheDirectory:path]; + return [self initWithNamespace:ns diskCacheDirectory:nil]; } - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns - diskCacheDirectory:(nonnull NSString *)directory { + diskCacheDirectory:(nullable NSString *)directory { return [self initWithNamespace:ns diskCacheDirectory:directory config:SDImageCacheConfig.defaultCacheConfig]; } - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns - diskCacheDirectory:(nonnull NSString *)directory + diskCacheDirectory:(nullable NSString *)directory config:(nullable SDImageCacheConfig *)config { if ((self = [super init])) { - NSString *namespacePrefix = config.namespacePrefix; - if (!namespacePrefix) { - namespacePrefix = @""; - } - NSString *fullNamespace = [namespacePrefix stringByAppendingString:ns]; + NSAssert(ns, @"Cache namespace should not be nil"); // Create IO serial queue _ioQueue = dispatch_queue_create("com.hackemist.SDImageCache", DISPATCH_QUEUE_SERIAL); @@ -78,9 +73,9 @@ // Init the disk cache if (directory != nil) { - _diskCachePath = [directory stringByAppendingPathComponent:fullNamespace]; + _diskCachePath = [directory stringByAppendingPathComponent:ns]; } else { - NSString *path = [self makeDiskCachePath:ns]; + NSString *path = [[[self userCacheDirectory] stringByAppendingPathComponent:@"com.hackemist.SDImageCache"] stringByAppendingPathComponent:ns]; _diskCachePath = path; } @@ -126,17 +121,19 @@ return [self.diskCache cachePathForKey:key]; } -- (nullable NSString *)makeDiskCachePath:(nonnull NSString *)fullNamespace { +- (nullable NSString *)userCacheDirectory { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - return [paths.firstObject stringByAppendingPathComponent:fullNamespace]; + return paths.firstObject; } - (void)migrateDiskCacheDirectory { if ([self.diskCache isKindOfClass:[SDDiskCache class]]) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - NSString *newDefaultPath = [[self makeDiskCachePath:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDImageCache.default"]; - NSString *oldDefaultPath = [[self makeDiskCachePath:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDWebImageCache.default"]; + // ~/Library/Caches/com.hackemist.SDImageCache/default/ + NSString *newDefaultPath = [[[self userCacheDirectory] stringByAppendingPathComponent:@"com.hackemist.SDImageCache"] stringByAppendingPathComponent:@"default"]; + // ~/Library/Caches/default/com.hackemist.SDImageCache.default/ + NSString *oldDefaultPath = [[[self userCacheDirectory] stringByAppendingPathComponent:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDWebImageCache.default"]; dispatch_async(self.ioQueue, ^{ [((SDDiskCache *)self.diskCache) moveCacheDirectoryFromPath:oldDefaultPath toPath:newDefaultPath]; }); diff --git a/SDWebImage/SDImageCacheConfig.h b/SDWebImage/SDImageCacheConfig.h index d7f86107..24f47c45 100644 --- a/SDWebImage/SDImageCacheConfig.h +++ b/SDWebImage/SDImageCacheConfig.h @@ -99,12 +99,6 @@ typedef NS_ENUM(NSUInteger, SDImageCacheConfigExpireType) { */ @property (assign, nonatomic) SDImageCacheConfigExpireType diskCacheExpireType; -/** - * The namespace prefix of cache. It's used to prefix the namespace you provide to the caches's initializer. You 'd better name it with reverse domain name notation and keep the final dot. - * Defautls to `com.hackemist.SDImageCache.`, which will prefix your namespace such as `default` to final `com.hackemist.SDImageCache.default`. If you specify nil, it will be treated equals to an empty string. - */ -@property (copy, nonatomic, nullable) NSString *namespacePrefix; - /** * The custom file manager for disk cache. Pass nil to let disk cache choose the proper file manager. * Defaults to nil. diff --git a/SDWebImage/SDImageCacheConfig.m b/SDWebImage/SDImageCacheConfig.m index 99a035f8..085e2d79 100644 --- a/SDWebImage/SDImageCacheConfig.m +++ b/SDWebImage/SDImageCacheConfig.m @@ -34,7 +34,6 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week _maxCacheAge = kDefaultCacheMaxCacheAge; _maxCacheSize = 0; _diskCacheExpireType = SDImageCacheConfigExpireTypeModificationDate; - _namespacePrefix = @"com.hackemist.SDImageCache."; _memoryCacheClass = [SDMemoryCache class]; _diskCacheClass = [SDDiskCache class]; } @@ -54,7 +53,6 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week config.maxMemoryCost = self.maxMemoryCost; config.maxMemoryCount = self.maxMemoryCount; config.diskCacheExpireType = self.diskCacheExpireType; - config.namespacePrefix = self.namespacePrefix; config.fileManager = self.fileManager; // NSFileManager does not conform to NSCopying, just pass the reference config.memoryCacheClass = self.memoryCacheClass; config.diskCacheClass = self.diskCacheClass; diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index b2bdd77c..dda01837 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -356,8 +356,7 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; SDImageCacheConfig *config = [[SDImageCacheConfig alloc] init]; config.memoryCacheClass = [SDWebImageTestMemoryCache class]; NSString *nameSpace = @"SDWebImageTestMemoryCache"; - NSString *cacheDictionary = [self makeDiskCachePath:nameSpace]; - SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:nameSpace diskCacheDirectory:cacheDictionary config:config]; + SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:nameSpace diskCacheDirectory:nil config:config]; SDWebImageTestMemoryCache *memCache = cache.memCache; expect([memCache isKindOfClass:[SDWebImageTestMemoryCache class]]).to.beTruthy(); } @@ -366,8 +365,7 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; SDImageCacheConfig *config = [[SDImageCacheConfig alloc] init]; config.diskCacheClass = [SDWebImageTestDiskCache class]; NSString *nameSpace = @"SDWebImageTestDiskCache"; - NSString *cacheDictionary = [self makeDiskCachePath:nameSpace]; - SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:nameSpace diskCacheDirectory:cacheDictionary config:config]; + SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:nameSpace diskCacheDirectory:nil config:config]; SDWebImageTestDiskCache *diskCache = cache.diskCache; expect([diskCache isKindOfClass:[SDWebImageTestDiskCache class]]).to.beTruthy(); } @@ -378,8 +376,8 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; config.fileManager = fileManager; // Fake to store a.png into old path - NSString *newDefaultPath = [[self makeDiskCachePath:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDImageCache.default"]; - NSString *oldDefaultPath = [[self makeDiskCachePath:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDWebImageCache.default"]; + NSString *newDefaultPath = [[[self userCacheDirectory] stringByAppendingPathComponent:@"com.hackemist.SDImageCache"] stringByAppendingPathComponent:@"default"]; + NSString *oldDefaultPath = [[[self userCacheDirectory] stringByAppendingPathComponent:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDWebImageCache.default"]; [fileManager createDirectoryAtPath:oldDefaultPath withIntermediateDirectories:YES attributes:nil error:nil]; [fileManager createFileAtPath:[oldDefaultPath stringByAppendingPathComponent:@"a.png"] contents:[NSData dataWithContentsOfFile:[self testPNGPath]] attributes:nil]; // Call migration @@ -609,9 +607,9 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; return [testBundle pathForResource:@"TestImage" ofType:@"png"]; } -- (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace { +- (nullable NSString *)userCacheDirectory { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - return [paths[0] stringByAppendingPathComponent:fullNamespace]; + return paths.firstObject; } @end From 1fc1de5da93e88f061c5c3f60b278048ff789152 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 17 Nov 2018 13:18:45 +0800 Subject: [PATCH 289/361] Update the migration guide for cache path --- Docs/SDWebImage-5.0-Migration-guide.md | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/Docs/SDWebImage-5.0-Migration-guide.md b/Docs/SDWebImage-5.0-Migration-guide.md index e684823e..96a6038c 100644 --- a/Docs/SDWebImage-5.0-Migration-guide.md +++ b/Docs/SDWebImage-5.0-Migration-guide.md @@ -62,21 +62,9 @@ By taking the advantage of the [Custom Loader](https://github.com/rs/SDWebImage/ #### Cache -`SDImageCache` in 5.x, use `~/Library/com.hackemist.SDImageCache.default` as default cache path. However, 4.x use `~/Library/com.hackemist.SDWebImageCache.default`. If you have images in cache, it may be lost during migration. +`SDImageCache` in 5.x, use `~/Library/Caches/com.hackemist.SDImageCache/default/` as default cache path. However, 4.x use `~/Library/Caches/default/com.hackemist.SDWebImageCache.default/`. And don't be worried, we will do the migration automatically once the shared cache initialized. -If you still want to keep the 4.x default cache path, you can custom the cache path prefix using `namespacePrefix` property. - -+ Objective-C - -```objective-c -SDImageCacheConfig.defaultCacheConfig.namespacePrefix = @"com.hackemist.SDWebImageCache."; -``` - -+ Swift - -```swift -SDImageCacheConfig.`default`.namespacePrefix = "com.hackemist.SDWebImageCache." -``` +However, if you have some other custom namespace cache instance, you should try to do migration by your own. But typically, since the cache is designed to be invalid at any time, you'd better not to bind some important logic related on that cache path changes. #### Prefetcher From 95dba7307d20708cc2745e43e7f172fff85a5f5c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 10 Dec 2018 13:26:32 +0800 Subject: [PATCH 290/361] Update the migration guide for cache path about 5.0.0-beta version --- Docs/SDWebImage-5.0-Migration-guide.md | 2 ++ SDWebImage/SDImageCache.m | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Docs/SDWebImage-5.0-Migration-guide.md b/Docs/SDWebImage-5.0-Migration-guide.md index 96a6038c..dee4e681 100644 --- a/Docs/SDWebImage-5.0-Migration-guide.md +++ b/Docs/SDWebImage-5.0-Migration-guide.md @@ -66,6 +66,8 @@ By taking the advantage of the [Custom Loader](https://github.com/rs/SDWebImage/ However, if you have some other custom namespace cache instance, you should try to do migration by your own. But typically, since the cache is designed to be invalid at any time, you'd better not to bind some important logic related on that cache path changes. +And, if you're previously using any version from `5.0.0-beta` to `5.0.0-beta3`, please note that the cache folder is been temporarily moved to `~/Library/Caches/default/com.hackemist.SDImageCache.default/`, however, the final release version of 5.0.0 use the path above. If you upgrade from those beta version, you may need manually do migration, check `+[SDDiskCache moveCacheDirectoryFromPath:toPath:]` for detail information. + #### Prefetcher `SDWebImagePrefetcher` in 5.x, change the concept of fetching batch of URLs. Now, each time you call `prefetchURLs:`, you will get a token which represents the specified URLs list. It does not cancel the previous URLs which is prefetching, which make the shared prefetcher behaves more intuitively. diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index db5a02ea..4007ce1d 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -132,7 +132,7 @@ dispatch_once(&onceToken, ^{ // ~/Library/Caches/com.hackemist.SDImageCache/default/ NSString *newDefaultPath = [[[self userCacheDirectory] stringByAppendingPathComponent:@"com.hackemist.SDImageCache"] stringByAppendingPathComponent:@"default"]; - // ~/Library/Caches/default/com.hackemist.SDImageCache.default/ + // ~/Library/Caches/default/com.hackemist.SDWebImageCache.default/ NSString *oldDefaultPath = [[[self userCacheDirectory] stringByAppendingPathComponent:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDWebImageCache.default"]; dispatch_async(self.ioQueue, ^{ [((SDDiskCache *)self.diskCache) moveCacheDirectoryFromPath:oldDefaultPath toPath:newDefaultPath]; From 1d540d3cb7c3f368bdde6db308914b3d19aff923 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 10 Dec 2018 20:34:10 +0800 Subject: [PATCH 291/361] Fix the typo in the 5.0 migration guide --- Docs/SDWebImage-5.0-Migration-guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Docs/SDWebImage-5.0-Migration-guide.md b/Docs/SDWebImage-5.0-Migration-guide.md index dee4e681..c9d07cdf 100644 --- a/Docs/SDWebImage-5.0-Migration-guide.md +++ b/Docs/SDWebImage-5.0-Migration-guide.md @@ -64,9 +64,9 @@ By taking the advantage of the [Custom Loader](https://github.com/rs/SDWebImage/ `SDImageCache` in 5.x, use `~/Library/Caches/com.hackemist.SDImageCache/default/` as default cache path. However, 4.x use `~/Library/Caches/default/com.hackemist.SDWebImageCache.default/`. And don't be worried, we will do the migration automatically once the shared cache initialized. -However, if you have some other custom namespace cache instance, you should try to do migration by your own. But typically, since the cache is designed to be invalid at any time, you'd better not to bind some important logic related on that cache path changes. +However, if you have some other custom namespace cache instance, you should try to do migration by yourself. But typically, since the cache is designed to be invalid at any time, you'd better not to bind some important logic related on that cache path changes. -And, if you're previously using any version from `5.0.0-beta` to `5.0.0-beta3`, please note that the cache folder is been temporarily moved to `~/Library/Caches/default/com.hackemist.SDImageCache.default/`, however, the final release version of 5.0.0 use the path above. If you upgrade from those beta version, you may need manually do migration, check `+[SDDiskCache moveCacheDirectoryFromPath:toPath:]` for detail information. +And, if you're previously using any version from `5.0.0-beta` to `5.0.0-beta3`, please note that the cache folder has been temporarily moved to `~/Library/Caches/default/com.hackemist.SDImageCache.default/`, however, the final release version of 5.0.0 use the path above. If you upgrade from those beta version, you may need manually do migration, check `+[SDDiskCache moveCacheDirectoryFromPath:toPath:]` for detail information. #### Prefetcher From 9617a344082b67b760ef1e97abc0668a342d11dd Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 11 Oct 2018 17:44:18 +0800 Subject: [PATCH 292/361] Fix background download operation FIx background download Add task check when operation will deallocated && tidy code Tidy code further Tidy further --- SDWebImage/SDWebImageDownloaderOperation.m | 49 +++++++++++----------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 427d939e..399cbd0e 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -65,6 +65,11 @@ typedef NSMutableDictionary SDCallbacksDictionary; @synthesize executing = _executing; @synthesize finished = _finished; +- (void)dealloc { + // Edge case if user call [SDWebImageDownloaderOperation start] directly and deallocated it. + [self cancel]; +} + - (nonnull instancetype)init { return [self initWithRequest:nil inSession:nil options:0]; } @@ -88,6 +93,9 @@ typedef NSMutableDictionary SDCallbacksDictionary; _unownedSession = session; _callbacksLock = dispatch_semaphore_create(1); _coderQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderOperationCoderQueue", DISPATCH_QUEUE_SERIAL); +#if SD_UIKIT + _backgroundTaskId = UIBackgroundTaskInvalid; +#endif } return self; } @@ -141,14 +149,7 @@ typedef NSMutableDictionary SDCallbacksDictionary; __weak __typeof__ (self) wself = self; UIApplication * app = [UIApplicationClass performSelector:@selector(sharedApplication)]; self.backgroundTaskId = [app beginBackgroundTaskWithExpirationHandler:^{ - __strong __typeof (wself) sself = wself; - - if (sself) { - [sself cancel]; - - [app endBackgroundTask:sself.backgroundTaskId]; - sself.backgroundTaskId = UIBackgroundTaskInvalid; - } + [wself cancel]; }]; } #endif @@ -212,18 +213,6 @@ typedef NSMutableDictionary SDCallbacksDictionary; [self done]; return; } - -#if SD_UIKIT - Class UIApplicationClass = NSClassFromString(@"UIApplication"); - if(!UIApplicationClass || ![UIApplicationClass respondsToSelector:@selector(sharedApplication)]) { - return; - } - if (self.backgroundTaskId != UIBackgroundTaskInvalid) { - UIApplication * app = [UIApplication performSelector:@selector(sharedApplication)]; - [app endBackgroundTask:self.backgroundTaskId]; - self.backgroundTaskId = UIBackgroundTaskInvalid; - } -#endif } - (void)cancel { @@ -262,11 +251,23 @@ typedef NSMutableDictionary SDCallbacksDictionary; SD_LOCK(self.callbacksLock); [self.callbackBlocks removeAllObjects]; SD_UNLOCK(self.callbacksLock); - self.dataTask = nil; - if (self.ownedSession) { - [self.ownedSession invalidateAndCancel]; - self.ownedSession = nil; + @synchronized (self) { + self.dataTask = nil; + + if (self.ownedSession) { + [self.ownedSession invalidateAndCancel]; + self.ownedSession = nil; + } + +#if SD_UIKIT + if (self.backgroundTaskId != UIBackgroundTaskInvalid) { + // If backgroundTaskId != UIBackgroundTaskInvalid, sharedApplication is always exist + UIApplication * app = [UIApplication performSelector:@selector(sharedApplication)]; + [app endBackgroundTask:self.backgroundTaskId]; + self.backgroundTaskId = UIBackgroundTaskInvalid; + } +#endif } } From de74bdca80679a2316befd4f0a377ab9f10cae2f Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 26 Dec 2018 20:29:09 +0800 Subject: [PATCH 293/361] Remove edge case check --- SDWebImage/SDWebImageDownloaderOperation.m | 5 ----- 1 file changed, 5 deletions(-) diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 399cbd0e..65d568bd 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -65,11 +65,6 @@ typedef NSMutableDictionary SDCallbacksDictionary; @synthesize executing = _executing; @synthesize finished = _finished; -- (void)dealloc { - // Edge case if user call [SDWebImageDownloaderOperation start] directly and deallocated it. - [self cancel]; -} - - (nonnull instancetype)init { return [self initWithRequest:nil inSession:nil options:0]; } From 6dd92d11ff99138297614d1b0204b21b9a231096 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 3 Jan 2019 15:11:24 +0800 Subject: [PATCH 294/361] Use the memory bytes size, instead of pixel size to calculate the memory cost function --- SDWebImage/SDAnimatedImage.m | 30 ++++++++++++++++++++++++++++ SDWebImage/SDImageCacheConfig.h | 5 +++-- SDWebImage/UIImage+MemoryCacheCost.h | 7 ++++--- SDWebImage/UIImage+MemoryCacheCost.m | 14 ++++++++++--- 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index d2df36d0..81148d08 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -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 diff --git a/SDWebImage/SDImageCacheConfig.h b/SDWebImage/SDImageCacheConfig.h index 24f47c45..6d24ad93 100644 --- a/SDWebImage/SDImageCacheConfig.h +++ b/SDWebImage/SDImageCacheConfig.h @@ -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; diff --git a/SDWebImage/UIImage+MemoryCacheCost.h b/SDWebImage/UIImage+MemoryCacheCost.h index 9ecf5b94..ba63928e 100644 --- a/SDWebImage/UIImage+MemoryCacheCost.h +++ b/SDWebImage/UIImage+MemoryCacheCost.h @@ -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; diff --git a/SDWebImage/UIImage+MemoryCacheCost.m b/SDWebImage/UIImage+MemoryCacheCost.m index 6f1375d7..b0883b1f 100644 --- a/SDWebImage/UIImage+MemoryCacheCost.m +++ b/SDWebImage/UIImage+MemoryCacheCost.m @@ -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) From ccf5541a7d77b0318674bde503e4c95d42b61213 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Mon, 7 Jan 2019 22:59:46 +0800 Subject: [PATCH 295/361] Fix memory cost override for SDAnimatedImage --- SDWebImage/SDAnimatedImage.m | 6 +----- SDWebImage/UIImage+MemoryCacheCost.h | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index 81148d08..6b779289 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -429,13 +429,9 @@ static NSArray *SDBundlePreferredScales() { @end -@interface SDAnimatedImage (MemoryCacheCost) - -@end - @implementation SDAnimatedImage (MemoryCacheCost) -- (NSUInteger)sd_imageMemoryCost { +- (NSUInteger)sd_memoryCost { NSNumber *value = objc_getAssociatedObject(self, @selector(sd_memoryCost)); if (value != nil) { return value.unsignedIntegerValue; diff --git a/SDWebImage/UIImage+MemoryCacheCost.h b/SDWebImage/UIImage+MemoryCacheCost.h index ba63928e..262c9964 100644 --- a/SDWebImage/UIImage+MemoryCacheCost.h +++ b/SDWebImage/UIImage+MemoryCacheCost.h @@ -16,8 +16,8 @@ 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. + @note Note that because of the limitations of category 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 frame's total bytes. */ @property (assign, nonatomic) NSUInteger sd_memoryCost; From cf1d993b97fb9b5141d82faae121fa60370074e0 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 8 Jan 2019 13:50:52 +0800 Subject: [PATCH 296/361] Move the cache storage logic after download, into a single function to enhance the readability --- SDWebImage/SDWebImageManager.m | 103 +++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 44 deletions(-) diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index a18b0a24..4f30bcf9 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -176,6 +176,7 @@ static id _defaultImageLoader; #pragma mark - Private +// Query cache process - (void)callCacheProcessForOperation:(nonnull SDWebImageCombinedOperation *)operation url:(nullable NSURL *)url options:(SDWebImageOptions)options @@ -203,6 +204,7 @@ static id _defaultImageLoader; } } +// Download process - (void)callDownloadProcessForOperation:(nonnull SDWebImageCombinedOperation *)operation url:(nullable NSURL *)url options:(SDWebImageOptions)options @@ -272,50 +274,7 @@ static id _defaultImageLoader; SD_UNLOCK(self.failedURLsLock); } - SDImageCacheType storeCacheType = SDImageCacheTypeAll; - if (context[SDWebImageContextStoreCacheType]) { - storeCacheType = [context[SDWebImageContextStoreCacheType] integerValue]; - } - id cacheKeyFilter = context[SDWebImageContextCacheKeyFilter]; - NSString *key = [self cacheKeyForURL:url cacheKeyFilter:cacheKeyFilter]; - id transformer = context[SDWebImageContextImageTransformer]; - id cacheSerializer = context[SDWebImageContextCacheSerializer]; - if (downloadedImage && (!downloadedImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage)) && transformer) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - @autoreleasepool { - UIImage *transformedImage = [transformer transformedImageWithImage:downloadedImage forKey:key]; - if (transformedImage && finished) { - NSString *transformerKey = [transformer transformerKey]; - NSString *cacheKey = SDTransformedKeyForKey(key, transformerKey); - BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage]; - NSData *cacheData; - // pass nil if the image was transformed, so we can recalculate the data from the image - if (cacheSerializer) { - cacheData = [cacheSerializer cacheDataWithImage:transformedImage originalData:(imageWasTransformed ? nil : downloadedData) imageURL:url]; - } else { - cacheData = (imageWasTransformed ? nil : downloadedData); - } - [self.imageCache storeImage:transformedImage imageData:cacheData forKey:cacheKey cacheType:storeCacheType completion:nil]; - } - - [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; - } - }); - } else { - if (downloadedImage && finished) { - if (cacheSerializer) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - @autoreleasepool { - NSData *cacheData = [cacheSerializer cacheDataWithImage:downloadedImage originalData:downloadedData imageURL:url]; - [self.imageCache storeImage:downloadedImage imageData:cacheData forKey:key cacheType:storeCacheType completion:nil]; - } - }); - } else { - [self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key cacheType:storeCacheType completion:nil]; - } - } - [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:downloadedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; - } + [self callStoreCacheProcessForOperation:strongOperation url:url options:options context:context downloadedImage:downloadedImage downloadedData:downloadedData finished:finished progress:progressBlock completed:completedBlock]; } if (finished) { @@ -332,6 +291,62 @@ static id _defaultImageLoader; } } +// Store cache process +- (void)callStoreCacheProcessForOperation:(nonnull SDWebImageCombinedOperation *)operation + url:(nullable NSURL *)url + options:(SDWebImageOptions)options + context:(SDWebImageContext *)context + downloadedImage:(nullable UIImage *)downloadedImage + downloadedData:(nullable NSData *)downloadedData + finished:(BOOL)finished + progress:(nullable SDImageLoaderProgressBlock)progressBlock + completed:(nullable SDInternalCompletionBlock)completedBlock { + SDImageCacheType storeCacheType = SDImageCacheTypeAll; + if (context[SDWebImageContextStoreCacheType]) { + storeCacheType = [context[SDWebImageContextStoreCacheType] integerValue]; + } + id cacheKeyFilter = context[SDWebImageContextCacheKeyFilter]; + NSString *key = [self cacheKeyForURL:url cacheKeyFilter:cacheKeyFilter]; + id transformer = context[SDWebImageContextImageTransformer]; + id cacheSerializer = context[SDWebImageContextCacheSerializer]; + if (downloadedImage && (!downloadedImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage)) && transformer) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + @autoreleasepool { + UIImage *transformedImage = [transformer transformedImageWithImage:downloadedImage forKey:key]; + if (transformedImage && finished) { + NSString *transformerKey = [transformer transformerKey]; + NSString *cacheKey = SDTransformedKeyForKey(key, transformerKey); + BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage]; + NSData *cacheData; + // pass nil if the image was transformed, so we can recalculate the data from the image + if (cacheSerializer && (storeCacheType == SDImageCacheTypeDisk || storeCacheType == SDImageCacheTypeAll)) { + cacheData = [cacheSerializer cacheDataWithImage:transformedImage originalData:(imageWasTransformed ? nil : downloadedData) imageURL:url]; + } else { + cacheData = (imageWasTransformed ? nil : downloadedData); + } + [self.imageCache storeImage:transformedImage imageData:cacheData forKey:cacheKey cacheType:storeCacheType completion:nil]; + } + + [self callCompletionBlockForOperation:operation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; + } + }); + } else { + if (downloadedImage && finished) { + if (cacheSerializer && (storeCacheType == SDImageCacheTypeDisk || storeCacheType == SDImageCacheTypeAll)) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + @autoreleasepool { + NSData *cacheData = [cacheSerializer cacheDataWithImage:downloadedImage originalData:downloadedData imageURL:url]; + [self.imageCache storeImage:downloadedImage imageData:cacheData forKey:key cacheType:storeCacheType completion:nil]; + } + }); + } else { + [self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key cacheType:storeCacheType completion:nil]; + } + } + [self callCompletionBlockForOperation:operation completion:completedBlock image:downloadedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; + } +} + #pragma mark - Helper - (void)safelyRemoveOperationFromRunning:(nullable SDWebImageCombinedOperation*)operation { From a1106d51f0f38a962a5153d8e5f4097aa78b0b54 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 8 Jan 2019 14:05:05 +0800 Subject: [PATCH 297/361] Move the block failed url logic into a separate method, filter the error codes not inside NSURLErrorDomain --- SDWebImage/SDWebImageManager.m | 42 ++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 4f30bcf9..ae309220 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -247,20 +247,7 @@ static id _defaultImageLoader; // Image refresh hit the NSURLCache cache, do not call the completion block } else if (error) { [self callCompletionBlockForOperation:strongOperation completion:completedBlock error:error url:url]; - BOOL shouldBlockFailedURL; - // Check whether we should block failed url - if ([self.delegate respondsToSelector:@selector(imageManager:shouldBlockFailedURL:withError:)]) { - shouldBlockFailedURL = [self.delegate imageManager:self shouldBlockFailedURL:url withError:error]; - } else { - shouldBlockFailedURL = ( error.code != NSURLErrorNotConnectedToInternet - && error.code != NSURLErrorCancelled - && error.code != NSURLErrorTimedOut - && error.code != NSURLErrorInternationalRoamingOff - && error.code != NSURLErrorDataNotAllowed - && error.code != NSURLErrorCannotFindHost - && error.code != NSURLErrorCannotConnectToHost - && error.code != NSURLErrorNetworkConnectionLost); - } + BOOL shouldBlockFailedURL = [self shouldBlockFailedURLWithURL:url error:error]; if (shouldBlockFailedURL) { SD_LOCK(self.failedURLsLock); @@ -380,6 +367,33 @@ static id _defaultImageLoader; }); } +- (BOOL)shouldBlockFailedURLWithURL:(nonnull NSURL *)url + error:(nonnull NSError *)error { + // Check whether we should block failed url + BOOL shouldBlockFailedURL; + if ([self.delegate respondsToSelector:@selector(imageManager:shouldBlockFailedURL:withError:)]) { + shouldBlockFailedURL = [self.delegate imageManager:self shouldBlockFailedURL:url withError:error]; + } else { + NSString *domain = error.domain; + NSInteger code = error.code; + if ([domain isEqualToString:NSURLErrorDomain]) { + shouldBlockFailedURL = ( code != NSURLErrorNotConnectedToInternet + && code != NSURLErrorCancelled + && code != NSURLErrorTimedOut + && code != NSURLErrorInternationalRoamingOff + && code != NSURLErrorDataNotAllowed + && code != NSURLErrorCannotFindHost + && code != NSURLErrorCannotConnectToHost + && code != NSURLErrorNetworkConnectionLost); + } else { + // Custom loader, don't do extra error code check + shouldBlockFailedURL = NO; + } + } + + return shouldBlockFailedURL; +} + - (SDWebImageContext *)processedContextWithContext:(SDWebImageContext *)context { SDWebImageMutableContext *mutableContext = [SDWebImageMutableContext dictionary]; From e71e58ea6d935ee9326deacc7ab75c0f2a92d192 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 9 Jan 2019 22:03:06 +0800 Subject: [PATCH 298/361] Revert failed block processing logic --- SDWebImage/SDWebImageManager.m | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index ae309220..0a91d89d 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -374,21 +374,14 @@ static id _defaultImageLoader; if ([self.delegate respondsToSelector:@selector(imageManager:shouldBlockFailedURL:withError:)]) { shouldBlockFailedURL = [self.delegate imageManager:self shouldBlockFailedURL:url withError:error]; } else { - NSString *domain = error.domain; - NSInteger code = error.code; - if ([domain isEqualToString:NSURLErrorDomain]) { - shouldBlockFailedURL = ( code != NSURLErrorNotConnectedToInternet - && code != NSURLErrorCancelled - && code != NSURLErrorTimedOut - && code != NSURLErrorInternationalRoamingOff - && code != NSURLErrorDataNotAllowed - && code != NSURLErrorCannotFindHost - && code != NSURLErrorCannotConnectToHost - && code != NSURLErrorNetworkConnectionLost); - } else { - // Custom loader, don't do extra error code check - shouldBlockFailedURL = NO; - } + shouldBlockFailedURL = ( error.code != NSURLErrorNotConnectedToInternet + && error.code != NSURLErrorCancelled + && error.code != NSURLErrorTimedOut + && error.code != NSURLErrorInternationalRoamingOff + && error.code != NSURLErrorDataNotAllowed + && error.code != NSURLErrorCannotFindHost + && error.code != NSURLErrorCannotConnectToHost + && error.code != NSURLErrorNetworkConnectionLost); } return shouldBlockFailedURL; From d90ca19d1b5b5d3d8544229812b5ca456fb4f296 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 26 Jan 2019 17:42:17 +0800 Subject: [PATCH 299/361] Revert the changes due to merge conflict. --- .../FLAnimatedImageView+WebCache.m | 215 ------- SDWebImage/SDWebImageWebPCoder.m | 551 ------------------ Tests/Tests/SDCategoriesTests.m | 101 ---- 3 files changed, 867 deletions(-) delete mode 100644 SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m delete mode 100644 SDWebImage/SDWebImageWebPCoder.m diff --git a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m deleted file mode 100644 index 71bd9886..00000000 --- a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m +++ /dev/null @@ -1,215 +0,0 @@ -/* - * This file is part of the SDWebImage package. - * (c) Olivier Poitrey - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#import "FLAnimatedImageView+WebCache.h" - -#if SD_UIKIT -#import "objc/runtime.h" -#import "UIView+WebCacheOperation.h" -#import "UIView+WebCache.h" -#import "NSData+ImageContentType.h" -#import "UIImageView+WebCache.h" -#import "UIImage+MultiFormat.h" -#import "UIImage+MemoryCacheCost.h" - -@interface UIView (PrivateWebCache) - -- (void)sd_internalSetImageWithURL:(nullable NSURL *)url - placeholderImage:(nullable UIImage *)placeholder - options:(SDWebImageOptions)options - operationKey:(nullable NSString *)operationKey - internalSetImageBlock:(nullable SDInternalSetImageBlock)setImageBlock - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDExternalCompletionBlock)completedBlock - context:(nullable NSDictionary *)context; - -@end - -static inline FLAnimatedImage * SDWebImageCreateFLAnimatedImage(FLAnimatedImageView *imageView, NSData *imageData) { - if ([NSData sd_imageFormatForImageData:imageData] != SDImageFormatGIF) { - return nil; - } - FLAnimatedImage *animatedImage; - // Compatibility in 4.x for lower version FLAnimatedImage. - if ([FLAnimatedImage instancesRespondToSelector:@selector(initWithAnimatedGIFData:optimalFrameCacheSize:predrawingEnabled:)]) { - animatedImage = [[FLAnimatedImage alloc] initWithAnimatedGIFData:imageData optimalFrameCacheSize:imageView.sd_optimalFrameCacheSize predrawingEnabled:imageView.sd_predrawingEnabled]; - } else { - animatedImage = [[FLAnimatedImage alloc] initWithAnimatedGIFData:imageData]; - } - return animatedImage; -} - -static inline NSUInteger SDWebImageMemoryCostFLAnimatedImage(FLAnimatedImage *animatedImage, UIImage *image) { - NSUInteger frameCacheSizeCurrent = animatedImage.frameCacheSizeCurrent; // [1...frame count], more suitable than raw frame count because FLAnimatedImage internal actually store a buffer size but not full frames (they called `window`) - NSUInteger pixelsPerFrame = animatedImage.size.width * animatedImage.size.height; // FLAnimatedImage does not support scale factor - NSUInteger animatedImageCost = frameCacheSizeCurrent * pixelsPerFrame; - - NSUInteger imageCost = image.size.height * image.size.width * image.scale * image.scale; // Same as normal cost calculation - imageCost = image.images ? (imageCost * image.images.count) : imageCost; - - return animatedImageCost + imageCost; -} - -@implementation UIImage (FLAnimatedImage) - -- (FLAnimatedImage *)sd_FLAnimatedImage { - return objc_getAssociatedObject(self, @selector(sd_FLAnimatedImage)); -} - -- (void)setSd_FLAnimatedImage:(FLAnimatedImage *)sd_FLAnimatedImage { - objc_setAssociatedObject(self, @selector(sd_FLAnimatedImage), sd_FLAnimatedImage, OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -@end - -@implementation FLAnimatedImageView (WebCache) - -// These property based options will moved to `SDWebImageContext` in 5.x, to allow per-image-request level options instead of per-imageView-level options -- (NSUInteger)sd_optimalFrameCacheSize { - NSUInteger optimalFrameCacheSize = 0; - NSNumber *value = objc_getAssociatedObject(self, @selector(sd_optimalFrameCacheSize)); - if ([value isKindOfClass:[NSNumber class]]) { - optimalFrameCacheSize = value.unsignedShortValue; - } - return optimalFrameCacheSize; -} - -- (void)setSd_optimalFrameCacheSize:(NSUInteger)sd_optimalFrameCacheSize { - objc_setAssociatedObject(self, @selector(sd_optimalFrameCacheSize), @(sd_optimalFrameCacheSize), OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (BOOL)sd_predrawingEnabled { - BOOL predrawingEnabled = YES; - NSNumber *value = objc_getAssociatedObject(self, @selector(sd_predrawingEnabled)); - if ([value isKindOfClass:[NSNumber class]]) { - predrawingEnabled = value.boolValue; - } - return predrawingEnabled; -} - -- (void)setSd_predrawingEnabled:(BOOL)sd_predrawingEnabled { - objc_setAssociatedObject(self, @selector(sd_predrawingEnabled), @(sd_predrawingEnabled), OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (BOOL)sd_cacheFLAnimatedImage { - BOOL cacheFLAnimatedImage = YES; - NSNumber *value = objc_getAssociatedObject(self, @selector(sd_cacheFLAnimatedImage)); - if ([value isKindOfClass:[NSNumber class]]) { - cacheFLAnimatedImage = value.boolValue; - } - return cacheFLAnimatedImage; -} - -- (void)setSd_cacheFLAnimatedImage:(BOOL)sd_cacheFLAnimatedImage { - objc_setAssociatedObject(self, @selector(sd_cacheFLAnimatedImage), @(sd_cacheFLAnimatedImage), OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (void)sd_setImageWithURL:(nullable NSURL *)url { - [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil]; -} - -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder { - [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil]; -} - -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { - [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; -} - -- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { - [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; -} - -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { - [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock]; -} - -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { - [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; -} - -- (void)sd_setImageWithURL:(nullable NSURL *)url - placeholderImage:(nullable UIImage *)placeholder - options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDExternalCompletionBlock)completedBlock { - dispatch_group_t group = dispatch_group_create(); - __weak typeof(self)weakSelf = self; - [self sd_internalSetImageWithURL:url - placeholderImage:placeholder - options:options - operationKey:nil - internalSetImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { - __strong typeof(weakSelf)strongSelf = weakSelf; - if (!strongSelf) { - dispatch_group_leave(group); - return; - } - // Step 1. Check memory cache (associate object) - FLAnimatedImage *associatedAnimatedImage = image.sd_FLAnimatedImage; - if (associatedAnimatedImage) { - // Asscociated animated image exist - // FLAnimatedImage framework contains a bug that cause GIF been rotated if previous rendered image orientation is not Up. We have to call `setImage:` with non-nil image to reset the state. See `https://github.com/SDWebImage/SDWebImage/issues/2402` - strongSelf.image = associatedAnimatedImage.posterImage; - strongSelf.animatedImage = associatedAnimatedImage; - dispatch_group_leave(group); - return; - } - // Step 2. Check if original compressed image data is "GIF" - BOOL isGIF = (image.sd_imageFormat == SDImageFormatGIF || [NSData sd_imageFormatForImageData:imageData] == SDImageFormatGIF); - // Check if placeholder, which does not trigger a backup disk cache query - BOOL isPlaceholder = !imageData && image && cacheType == SDImageCacheTypeNone; - if (!isGIF || isPlaceholder) { - strongSelf.image = image; - strongSelf.animatedImage = nil; - dispatch_group_leave(group); - return; - } - __weak typeof(strongSelf) wweakSelf = strongSelf; - // Hack, mark we need should use dispatch group notify for completedBlock - objc_setAssociatedObject(group, &SDWebImageInternalSetImageGroupKey, @(YES), OBJC_ASSOCIATION_RETAIN_NONATOMIC); - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - __strong typeof(wweakSelf) sstrongSelf = wweakSelf; - if (!sstrongSelf || ![url isEqual:sstrongSelf.sd_imageURL]) { return ; } - // Step 3. Check if data exist or query disk cache - NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:url]; - __block NSData *gifData = imageData; - if (!gifData) { - gifData = [[SDImageCache sharedImageCache] diskImageDataForKey:key]; - } - // Step 4. Create FLAnimatedImage - FLAnimatedImage *animatedImage = SDWebImageCreateFLAnimatedImage(sstrongSelf, gifData); - dispatch_async(dispatch_get_main_queue(), ^{ - if (![url isEqual:sstrongSelf.sd_imageURL]) { return ; } - // Step 5. Set animatedImage or normal image - if (animatedImage) { - if (sstrongSelf.sd_cacheFLAnimatedImage && SDImageCache.sharedImageCache.config.shouldCacheImagesInMemory) { - image.sd_FLAnimatedImage = animatedImage; - image.sd_memoryCost = SDWebImageMemoryCostFLAnimatedImage(animatedImage, image); - // Update the memory cache - [SDImageCache.sharedImageCache removeImageForKey:key fromDisk:NO withCompletion:nil]; - [SDImageCache.sharedImageCache storeImage:image forKey:key toDisk:NO completion:nil]; - } - sstrongSelf.image = animatedImage.posterImage; - sstrongSelf.animatedImage = animatedImage; - } else { - sstrongSelf.image = image; - sstrongSelf.animatedImage = nil; - } - dispatch_group_leave(group); - }); - }); - } - progress:progressBlock - completed:completedBlock - context:@{SDWebImageInternalSetImageGroupKey: group}]; -} - -@end - -#endif diff --git a/SDWebImage/SDWebImageWebPCoder.m b/SDWebImage/SDWebImageWebPCoder.m deleted file mode 100644 index d1811e54..00000000 --- a/SDWebImage/SDWebImageWebPCoder.m +++ /dev/null @@ -1,551 +0,0 @@ -/* - * This file is part of the SDWebImage package. - * (c) Olivier Poitrey - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#ifdef SD_WEBP - -#import "SDWebImageWebPCoder.h" -#import "SDWebImageCoderHelper.h" -#import "NSImage+WebCache.h" -#import "UIImage+MultiFormat.h" -#import "SDWebImageImageIOCoder.h" -#if __has_include() && __has_include() && __has_include() && __has_include() -#import -#import -#import -#import -#else -#import "webp/decode.h" -#import "webp/encode.h" -#import "webp/demux.h" -#import "webp/mux.h" -#endif -#import - - -@implementation SDWebImageWebPCoder { - WebPIDecoder *_idec; -} - -- (void)dealloc { - if (_idec) { - WebPIDelete(_idec); - _idec = NULL; - } -} - -+ (instancetype)sharedCoder { - static SDWebImageWebPCoder *coder; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - coder = [[SDWebImageWebPCoder alloc] init]; - }); - return coder; -} - -#pragma mark - Decode -- (BOOL)canDecodeFromData:(nullable NSData *)data { - return ([NSData sd_imageFormatForImageData:data] == SDImageFormatWebP); -} - -- (BOOL)canIncrementallyDecodeFromData:(NSData *)data { - return ([NSData sd_imageFormatForImageData:data] == SDImageFormatWebP); -} - -- (UIImage *)decodedImageWithData:(NSData *)data { - if (!data) { - return nil; - } - - WebPData webpData; - WebPDataInit(&webpData); - webpData.bytes = data.bytes; - webpData.size = data.length; - WebPDemuxer *demuxer = WebPDemux(&webpData); - if (!demuxer) { - return nil; - } - - uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS); - - CGColorSpaceRef colorSpace = [self sd_colorSpaceWithDemuxer:demuxer]; - - if (!(flags & ANIMATION_FLAG)) { - // for static single webp image - UIImage *staticImage = [self sd_rawWebpImageWithData:webpData colorSpace:colorSpace]; - WebPDemuxDelete(demuxer); - CGColorSpaceRelease(colorSpace); - staticImage.sd_imageFormat = SDImageFormatWebP; - return staticImage; - } - - int loopCount = WebPDemuxGetI(demuxer, WEBP_FF_LOOP_COUNT); - int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH); - int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT); - CGBitmapInfo bitmapInfo; - // `CGBitmapContextCreate` does not support RGB888 on iOS. Where `CGImageCreate` supports. - if (!(flags & ALPHA_FLAG)) { - // RGBX8888 - bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaNoneSkipLast; - } else { - // RGBA8888 - bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast; - } - - CGContextRef canvas = CGBitmapContextCreate(NULL, canvasWidth, canvasHeight, 8, 0, SDCGColorSpaceGetDeviceRGB(), bitmapInfo); - if (!canvas) { - WebPDemuxDelete(demuxer); - CGColorSpaceRelease(colorSpace); - return nil; - } - - // for animated webp image - WebPIterator iter; - if (!WebPDemuxGetFrame(demuxer, 1, &iter)) { - WebPDemuxReleaseIterator(&iter); - WebPDemuxDelete(demuxer); - CGContextRelease(canvas); - CGColorSpaceRelease(colorSpace); - return nil; - } - - NSMutableArray *frames = [NSMutableArray array]; - - do { - @autoreleasepool { - UIImage *image = [self sd_drawnWebpImageWithCanvas:canvas iterator:iter colorSpace:colorSpace]; - if (!image) { - continue; - } - - int duration = iter.duration; - if (duration <= 10) { - // WebP standard says 0 duration is used for canvas updating but not showing image, but actually Chrome and other implementations set it to 100ms if duration is lower or equal than 10ms - // Some animated WebP images also created without duration, we should keep compatibility - duration = 100; - } - SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:image duration:duration / 1000.f]; - [frames addObject:frame]; - } - - } while (WebPDemuxNextFrame(&iter)); - - WebPDemuxReleaseIterator(&iter); - WebPDemuxDelete(demuxer); - CGContextRelease(canvas); - CGColorSpaceRelease(colorSpace); - - UIImage *animatedImage = [SDWebImageCoderHelper animatedImageWithFrames:frames]; - animatedImage.sd_imageLoopCount = loopCount; - animatedImage.sd_imageFormat = SDImageFormatWebP; - - return animatedImage; -} - -- (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished { - if (!_idec) { - // Progressive images need transparent, so always use premultiplied RGBA - _idec = WebPINewRGB(MODE_rgbA, NULL, 0, 0); - if (!_idec) { - return nil; - } - } - - UIImage *image; - - VP8StatusCode status = WebPIUpdate(_idec, data.bytes, data.length); - if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) { - return nil; - } - - int width = 0; - int height = 0; - int last_y = 0; - int stride = 0; - uint8_t *rgba = WebPIDecGetRGB(_idec, &last_y, &width, &height, &stride); - // last_y may be 0, means no enough bitmap data to decode, ignore this - if (width + height > 0 && last_y > 0 && height >= last_y) { - // Construct a UIImage from the decoded RGBA value array - size_t rgbaSize = last_y * stride; - CGDataProviderRef provider = - CGDataProviderCreateWithData(NULL, rgba, rgbaSize, NULL); - CGColorSpaceRef colorSpaceRef = SDCGColorSpaceGetDeviceRGB(); - - CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast; - size_t components = 4; - CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; - // Why to use last_y for image height is because of libwebp's bug (https://bugs.chromium.org/p/webp/issues/detail?id=362) - // It will not keep memory barrier safe on x86 architechure (macOS & iPhone simulator) but on ARM architecture (iPhone & iPad & tv & watch) it works great - // If different threads use WebPIDecGetRGB to grab rgba bitmap, it will contain the previous decoded bitmap data - // So this will cause our drawed image looks strange(above is the current part but below is the previous part) - // We only grab the last_y height and draw the last_y heigh instead of total height image - // Besides fix, this can enhance performance since we do not need to create extra bitmap - CGImageRef imageRef = CGImageCreate(width, last_y, 8, components * 8, components * width, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); - - CGDataProviderRelease(provider); - - if (!imageRef) { - return nil; - } - - CGContextRef canvas = CGBitmapContextCreate(NULL, width, height, 8, 0, SDCGColorSpaceGetDeviceRGB(), bitmapInfo); - if (!canvas) { - CGImageRelease(imageRef); - return nil; - } - - // Only draw the last_y image height, keep remains transparent, in Core Graphics coordinate system - CGContextDrawImage(canvas, CGRectMake(0, height - last_y, width, last_y), imageRef); - CGImageRef newImageRef = CGBitmapContextCreateImage(canvas); - CGImageRelease(imageRef); - if (!newImageRef) { - CGContextRelease(canvas); - return nil; - } - -#if SD_UIKIT || SD_WATCH - image = [[UIImage alloc] initWithCGImage:newImageRef]; -#else - image = [[UIImage alloc] initWithCGImage:newImageRef size:NSZeroSize]; -#endif - image.sd_imageFormat = SDImageFormatWebP; - CGImageRelease(newImageRef); - CGContextRelease(canvas); - } - - if (finished) { - if (_idec) { - WebPIDelete(_idec); - _idec = NULL; - } - } - - return image; -} - -- (UIImage *)decompressedImageWithImage:(UIImage *)image - data:(NSData *__autoreleasing _Nullable *)data - options:(nullable NSDictionary*)optionsDict { - // Decompress can help pre-draw the image and transfer the backing store to render process. - // Well, it can reduce the `App process memory usage` from Xcode, because the backing store is in `Other process` (render process). But it does not help for total memory usage for device. - // This logic is actually the same as Image/IO, reuse the code. The refactory has already done in 5.x - return [[SDWebImageImageIOCoder sharedCoder] decompressedImageWithImage:image data:data options:optionsDict]; -} - -- (nullable UIImage *)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef { - UIImage *image = [self sd_rawWebpImageWithData:iter.fragment colorSpace:colorSpaceRef]; - if (!image) { - return nil; - } - - size_t canvasWidth = CGBitmapContextGetWidth(canvas); - size_t canvasHeight = CGBitmapContextGetHeight(canvas); - CGSize size = CGSizeMake(canvasWidth, canvasHeight); - CGFloat tmpX = iter.x_offset; - CGFloat tmpY = size.height - iter.height - iter.y_offset; - CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height); - BOOL shouldBlend = iter.blend_method == WEBP_MUX_BLEND; - - // If not blend, cover the target image rect. (firstly clear then draw) - if (!shouldBlend) { - CGContextClearRect(canvas, imageRect); - } - CGContextDrawImage(canvas, imageRect, image.CGImage); - CGImageRef newImageRef = CGBitmapContextCreateImage(canvas); - -#if SD_UIKIT || SD_WATCH - image = [[UIImage alloc] initWithCGImage:newImageRef]; -#elif SD_MAC - image = [[UIImage alloc] initWithCGImage:newImageRef size:NSZeroSize]; -#endif - - CGImageRelease(newImageRef); - - if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { - CGContextClearRect(canvas, imageRect); - } - - return image; -} - -- (nullable UIImage *)sd_rawWebpImageWithData:(WebPData)webpData colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef { - WebPDecoderConfig config; - if (!WebPInitDecoderConfig(&config)) { - return nil; - } - - if (WebPGetFeatures(webpData.bytes, webpData.size, &config.input) != VP8_STATUS_OK) { - return nil; - } - - config.output.colorspace = config.input.has_alpha ? MODE_rgbA : MODE_RGB; - config.options.use_threads = 1; - - // Decode the WebP image data into a RGBA value array - if (WebPDecode(webpData.bytes, webpData.size, &config) != VP8_STATUS_OK) { - return nil; - } - - int width = config.input.width; - int height = config.input.height; - if (config.options.use_scaling) { - width = config.options.scaled_width; - height = config.options.scaled_height; - } - - // Construct a UIImage from the decoded RGBA value array - CGDataProviderRef provider = - CGDataProviderCreateWithData(NULL, config.output.u.RGBA.rgba, config.output.u.RGBA.size, FreeImageData); - CGBitmapInfo bitmapInfo; - // `CGBitmapContextCreate` does not support RGB888 on iOS. Where `CGImageCreate` supports. - if (!config.input.has_alpha) { - // RGB888 - bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaNone; - } else { - // RGBA8888 - bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast; - } - size_t components = config.input.has_alpha ? 4 : 3; - CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; - CGImageRef imageRef = CGImageCreate(width, height, 8, components * 8, components * width, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); - - CGDataProviderRelease(provider); - -#if SD_UIKIT || SD_WATCH - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef]; -#else - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; -#endif - CGImageRelease(imageRef); - - return image; -} - -// Create and return the correct colorspace by checking the ICC Profile -- (nonnull CGColorSpaceRef)sd_colorSpaceWithDemuxer:(nonnull WebPDemuxer *)demuxer CF_RETURNS_RETAINED { - // WebP contains ICC Profile should use the desired colorspace, instead of default device colorspace - // See: https://developers.google.com/speed/webp/docs/riff_container#color_profile - - CGColorSpaceRef colorSpaceRef = NULL; - uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS); - - if (flags & ICCP_FLAG) { - WebPChunkIterator chunk_iter; - int result = WebPDemuxGetChunk(demuxer, "ICCP", 1, &chunk_iter); - if (result) { - NSData *profileData = [NSData dataWithBytesNoCopy:(void *)chunk_iter.chunk.bytes length:chunk_iter.chunk.size freeWhenDone:NO]; - colorSpaceRef = CGColorSpaceCreateWithICCProfile((__bridge CFDataRef)profileData); - WebPDemuxReleaseChunkIterator(&chunk_iter); - } - } - - if (!colorSpaceRef) { - colorSpaceRef = SDCGColorSpaceGetDeviceRGB(); - CGColorSpaceRetain(colorSpaceRef); - } - - return colorSpaceRef; -} - -#pragma mark - Encode -- (BOOL)canEncodeToFormat:(SDImageFormat)format { - return (format == SDImageFormatWebP); -} - -- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format { - if (!image) { - return nil; - } - - NSData *data; - - NSArray *frames = [SDWebImageCoderHelper framesFromAnimatedImage:image]; - if (frames.count == 0) { - // for static single webp image - data = [self sd_encodedWebpDataWithImage:image]; - } else { - // for animated webp image - WebPMux *mux = WebPMuxNew(); - if (!mux) { - return nil; - } - for (size_t i = 0; i < frames.count; i++) { - SDWebImageFrame *currentFrame = frames[i]; - NSData *webpData = [self sd_encodedWebpDataWithImage:currentFrame.image]; - int duration = currentFrame.duration * 1000; - WebPMuxFrameInfo frame = { .bitstream.bytes = webpData.bytes, - .bitstream.size = webpData.length, - .duration = duration, - .id = WEBP_CHUNK_ANMF, - .dispose_method = WEBP_MUX_DISPOSE_BACKGROUND, // each frame will clear canvas - .blend_method = WEBP_MUX_NO_BLEND - }; - if (WebPMuxPushFrame(mux, &frame, 0) != WEBP_MUX_OK) { - WebPMuxDelete(mux); - return nil; - } - } - - int loopCount = (int)image.sd_imageLoopCount; - WebPMuxAnimParams params = { .bgcolor = 0, - .loop_count = loopCount - }; - if (WebPMuxSetAnimationParams(mux, ¶ms) != WEBP_MUX_OK) { - WebPMuxDelete(mux); - return nil; - } - - WebPData outputData; - WebPMuxError error = WebPMuxAssemble(mux, &outputData); - WebPMuxDelete(mux); - if (error != WEBP_MUX_OK) { - return nil; - } - data = [NSData dataWithBytes:outputData.bytes length:outputData.size]; - WebPDataClear(&outputData); - } - - return data; -} - -- (nullable NSData *)sd_encodedWebpDataWithImage:(nullable UIImage *)image { - if (!image) { - return nil; - } - - NSData *webpData; - CGImageRef imageRef = image.CGImage; - - size_t width = CGImageGetWidth(imageRef); - size_t height = CGImageGetHeight(imageRef); - if (width == 0 || width > WEBP_MAX_DIMENSION) { - return nil; - } - if (height == 0 || height > WEBP_MAX_DIMENSION) { - return nil; - } - - size_t bytesPerRow = CGImageGetBytesPerRow(imageRef); - CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); - CGImageAlphaInfo alphaInfo = bitmapInfo & kCGBitmapAlphaInfoMask; - CGBitmapInfo byteOrderInfo = bitmapInfo & kCGBitmapByteOrderMask; - BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone || - alphaInfo == kCGImageAlphaNoneSkipFirst || - alphaInfo == kCGImageAlphaNoneSkipLast); - BOOL byteOrderNormal = NO; - switch (byteOrderInfo) { - case kCGBitmapByteOrderDefault: { - byteOrderNormal = YES; - } break; - case kCGBitmapByteOrder32Little: { - } break; - case kCGBitmapByteOrder32Big: { - byteOrderNormal = YES; - } break; - default: break; - } - // If we can not get bitmap buffer, early return - CGDataProviderRef dataProvider = CGImageGetDataProvider(imageRef); - if (!dataProvider) { - return nil; - } - CFDataRef dataRef = CGDataProviderCopyData(dataProvider); - if (!dataRef) { - return nil; - } - - uint8_t *rgba = NULL; - // We could not assume that input CGImage's color mode is always RGB888/RGBA8888. Convert all other cases to target color mode using vImage - if (byteOrderNormal && ((alphaInfo == kCGImageAlphaNone) || (alphaInfo == kCGImageAlphaLast))) { - // If the input CGImage is already RGB888/RGBA8888 - rgba = (uint8_t *)CFDataGetBytePtr(dataRef); - } else { - // Convert all other cases to target color mode using vImage - vImageConverterRef convertor = NULL; - vImage_Error error = kvImageNoError; - - vImage_CGImageFormat srcFormat = { - .bitsPerComponent = (uint32_t)CGImageGetBitsPerComponent(imageRef), - .bitsPerPixel = (uint32_t)CGImageGetBitsPerPixel(imageRef), - .colorSpace = CGImageGetColorSpace(imageRef), - .bitmapInfo = bitmapInfo - }; - vImage_CGImageFormat destFormat = { - .bitsPerComponent = 8, - .bitsPerPixel = hasAlpha ? 32 : 24, - .colorSpace = SDCGColorSpaceGetDeviceRGB(), - .bitmapInfo = hasAlpha ? kCGImageAlphaLast | kCGBitmapByteOrderDefault : kCGImageAlphaNone | kCGBitmapByteOrderDefault // RGB888/RGBA8888 (Non-premultiplied to works for libwebp) - }; - - convertor = vImageConverter_CreateWithCGImageFormat(&srcFormat, &destFormat, NULL, kvImageNoFlags, &error); - if (error != kvImageNoError) { - CFRelease(dataRef); - return nil; - } - - vImage_Buffer src = { - .data = (uint8_t *)CFDataGetBytePtr(dataRef), - .width = width, - .height = height, - .rowBytes = bytesPerRow - }; - vImage_Buffer dest; - - error = vImageBuffer_Init(&dest, height, width, destFormat.bitsPerPixel, kvImageNoFlags); - if (error != kvImageNoError) { - CFRelease(dataRef); - return nil; - } - - // Convert input color mode to RGB888/RGBA8888 - error = vImageConvert_AnyToAny(convertor, &src, &dest, NULL, kvImageNoFlags); - if (error != kvImageNoError) { - CFRelease(dataRef); - return nil; - } - - rgba = dest.data; // Converted buffer - bytesPerRow = dest.rowBytes; // Converted bytePerRow - CFRelease(dataRef); - dataRef = NULL; - } - - uint8_t *data = NULL; // Output WebP data - float qualityFactor = 100; // WebP quality is 0-100 - // Encode RGB888/RGBA8888 buffer to WebP data - size_t size; - if (hasAlpha) { - size = WebPEncodeRGBA(rgba, (int)width, (int)height, (int)bytesPerRow, qualityFactor, &data); - } else { - size = WebPEncodeRGB(rgba, (int)width, (int)height, (int)bytesPerRow, qualityFactor, &data); - } - if (dataRef) { - CFRelease(dataRef); // free non-converted rgba buffer - dataRef = NULL; - } else { - free(rgba); // free converted rgba buffer - rgba = NULL; - } - - if (size) { - // success - webpData = [NSData dataWithBytes:data length:size]; - } - if (data) { - WebPFree(data); - } - - return webpData; -} - -static void FreeImageData(void *info, const void *data, size_t size) { - free((void *)data); -} - -@end - -#endif diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m index 829503b9..08415834 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDCategoriesTests.m @@ -53,110 +53,9 @@ #pragma mark - Helper -<<<<<<< HEAD - (NSString *)testJPEGPath { NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; return [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; -======= -- (void)testUIButtonSetImageWithURLHighlightedState { - XCTestExpectation *expectation = [self expectationWithDescription:@"UIButton setImageWithURL highlightedState"]; - - UIButton *button = [[UIButton alloc] init]; - NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; - [button sd_setImageWithURL:originalImageURL - forState:UIControlStateHighlighted - completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { - expect(image).toNot.beNil(); - expect(error).to.beNil(); - expect(originalImageURL).to.equal(imageURL); - expect([button imageForState:UIControlStateHighlighted]).to.equal(image); - [expectation fulfill]; - }]; - [self waitForExpectationsWithCommonTimeout]; -} - -- (void)testUIButtonSetBackgroundImageWithURLNormalState { - XCTestExpectation *expectation = [self expectationWithDescription:@"UIButton setBackgroundImageWithURL normalState"]; - - UIButton *button = [[UIButton alloc] init]; - NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; - [button sd_setBackgroundImageWithURL:originalImageURL - forState:UIControlStateNormal - completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { - expect(image).toNot.beNil(); - expect(error).to.beNil(); - expect(originalImageURL).to.equal(imageURL); - expect([button backgroundImageForState:UIControlStateNormal]).to.equal(image); - [expectation fulfill]; - }]; - [self waitForExpectationsWithCommonTimeout]; -} - -- (void)testFLAnimatedImageViewSetImageWithURL { - XCTestExpectation *expectation = [self expectationWithDescription:@"FLAnimatedImageView setImageWithURL"]; - - FLAnimatedImageView *imageView = [[FLAnimatedImageView alloc] init]; - NSURL *originalImageURL = [NSURL URLWithString:kTestGIFURL]; - - [imageView sd_setImageWithURL:originalImageURL - completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { - expect(image).toNot.beNil(); - expect(error).to.beNil(); - expect(originalImageURL).to.equal(imageURL); - - expect(imageView.animatedImage).toNot.beNil(); - [expectation fulfill]; - }]; - [self waitForExpectationsWithCommonTimeout]; -} - -- (void)testFLAnimatedImageViewSetImageWithPlaceholderFromCacheForSameURL { - XCTestExpectation *expectation = [self expectationWithDescription:@"FLAnimatedImageView set image with a placeholder which is the same as the cached image for same url"]; - /** - This is a really rare case. Some of user, who query the cache key for one GIF url and get the placeholder - Then use the placeholder and trigger a query for same url, because it will hit memory cache immediately, so the two `setImageBlock` call will have the same image instance and hard to distinguish. (Because we should not do async disk cache check for placeholder) - */ - - FLAnimatedImageView *imageView = [[FLAnimatedImageView alloc] init]; - NSURL *originalImageURL = [NSURL URLWithString:@"http://assets.sbnation.com/assets/2512203/dogflops.gif"]; - NSString *key = [SDWebImageManager.sharedManager cacheKeyForURL:originalImageURL]; - - [SDWebImageManager.sharedManager loadImageWithURL:originalImageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { - - UIImage *cachedImage = [SDImageCache.sharedImageCache imageFromCacheForKey:key]; - expect(cachedImage).toNot.beNil(); // Should be stored - cachedImage.sd_FLAnimatedImage = nil; // Cleanup the associated FLAnimatedImage instance - - [imageView sd_setImageWithURL:originalImageURL - placeholderImage:cachedImage - completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { - expect(image).to.equal(cachedImage); // should hit the cache and it's the same as placeholder - expect(imageView.animatedImage).toNot.beNil(); - [expectation fulfill]; - }]; - }]; - - [self waitForExpectationsWithCommonTimeout]; -} - -- (void)testUIViewImageProgressKVOWork { - XCTestExpectation *expectation = [self expectationWithDescription:@"UIView imageProgressKVO failed"]; - UIView *view = [[UIView alloc] init]; - NSURL *originalImageURL = [NSURL URLWithString:kTestJpegURL]; - - [view.sd_imageProgress addObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted)) options:NSKeyValueObservingOptionNew context:SDCategoriesTestsContext]; - - // Clear the disk cache to force download from network - [[SDImageCache sharedImageCache] removeImageForKey:kTestJpegURL withCompletion:^{ - [view sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 operationKey:nil setImageBlock:nil progress:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { - expect(view.sd_imageProgress.fractionCompleted).equal(1.0); - expect([view.sd_imageProgress.userInfo[NSStringFromSelector(_cmd)] boolValue]).equal(YES); - [expectation fulfill]; - }]; - }]; - [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:^(NSError * _Nullable error) { - [view.sd_imageProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted)) context:SDCategoriesTestsContext]; - }]; } - (NSString *)testGIFPath { From b3a3a26a043858bdfee13b169d106669916728af Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 27 Dec 2018 15:46:06 +0800 Subject: [PATCH 300/361] Renaming the disk cache size/cache age method and property with disk keyword, clarify the meaning --- SDWebImage/SDDiskCache.m | 4 ++-- SDWebImage/SDImageCache.h | 4 ++-- SDWebImage/SDImageCache.m | 4 ++-- SDWebImage/SDImageCacheConfig.h | 4 ++-- SDWebImage/SDImageCacheConfig.m | 8 ++++---- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/SDWebImage/SDDiskCache.m b/SDWebImage/SDDiskCache.m index 13e6f329..33354994 100644 --- a/SDWebImage/SDDiskCache.m +++ b/SDWebImage/SDDiskCache.m @@ -135,7 +135,7 @@ options:NSDirectoryEnumerationSkipsHiddenFiles errorHandler:NULL]; - NSDate *expirationDate = (self.config.maxCacheAge < 0) ? nil: [NSDate dateWithTimeIntervalSinceNow:-self.config.maxCacheAge]; + NSDate *expirationDate = (self.config.maxDiskAge < 0) ? nil: [NSDate dateWithTimeIntervalSinceNow:-self.config.maxDiskAge]; NSMutableDictionary *> *cacheFiles = [NSMutableDictionary dictionary]; NSUInteger currentCacheSize = 0; @@ -172,7 +172,7 @@ // If our remaining disk cache exceeds a configured maximum size, perform a second // size-based cleanup pass. We delete the oldest files first. - NSUInteger maxCacheSize = self.config.maxCacheSize; + NSUInteger maxCacheSize = self.config.maxDiskSize; if (maxCacheSize > 0 && currentCacheSize > maxCacheSize) { // Target half of our maximum cache size for this cleanup pass. const NSUInteger desiredCacheSize = maxCacheSize / 2; diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 558ead6a..4284cea8 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -323,12 +323,12 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { /** * Get the size used by the disk cache */ -- (NSUInteger)getSize; +- (NSUInteger)totalDiskSize; /** * Get the number of images in the disk cache */ -- (NSUInteger)getDiskCount; +- (NSUInteger)totalDiskCount; /** * Asynchronously calculate the disk cache's size. diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index e650a257..10506e82 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -564,7 +564,7 @@ #pragma mark - Cache Info -- (NSUInteger)getSize { +- (NSUInteger)totalDiskSize { __block NSUInteger size = 0; dispatch_sync(self.ioQueue, ^{ size = [self.diskCache totalSize]; @@ -572,7 +572,7 @@ return size; } -- (NSUInteger)getDiskCount { +- (NSUInteger)totalDiskCount { __block NSUInteger count = 0; dispatch_sync(self.ioQueue, ^{ count = [self.diskCache totalCount]; diff --git a/SDWebImage/SDImageCacheConfig.h b/SDWebImage/SDImageCacheConfig.h index 6d24ad93..97bf37e1 100644 --- a/SDWebImage/SDImageCacheConfig.h +++ b/SDWebImage/SDImageCacheConfig.h @@ -73,13 +73,13 @@ typedef NS_ENUM(NSUInteger, SDImageCacheConfigExpireType) { * Setting this to zero means that all cached files would be removed when do expiration check. * Defaults to 1 weak. */ -@property (assign, nonatomic) NSTimeInterval maxCacheAge; +@property (assign, nonatomic) NSTimeInterval maxDiskAge; /** * The maximum size of the disk cache, in bytes. * Defaults to 0. Which means there is no cache size limit. */ -@property (assign, nonatomic) NSUInteger maxCacheSize; +@property (assign, nonatomic) NSUInteger maxDiskSize; /** * The maximum "total cost" of the in-memory image cache. The cost function is the bytes size held in memory. diff --git a/SDWebImage/SDImageCacheConfig.m b/SDWebImage/SDImageCacheConfig.m index 085e2d79..831de835 100644 --- a/SDWebImage/SDImageCacheConfig.m +++ b/SDWebImage/SDImageCacheConfig.m @@ -31,8 +31,8 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week _shouldRemoveExpiredDataWhenEnterBackground = YES; _diskCacheReadingOptions = 0; _diskCacheWritingOptions = NSDataWritingAtomic; - _maxCacheAge = kDefaultCacheMaxCacheAge; - _maxCacheSize = 0; + _maxDiskAge = kDefaultCacheMaxCacheAge; + _maxDiskSize = 0; _diskCacheExpireType = SDImageCacheConfigExpireTypeModificationDate; _memoryCacheClass = [SDMemoryCache class]; _diskCacheClass = [SDDiskCache class]; @@ -48,8 +48,8 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week config.shouldRemoveExpiredDataWhenEnterBackground = self.shouldRemoveExpiredDataWhenEnterBackground; config.diskCacheReadingOptions = self.diskCacheReadingOptions; config.diskCacheWritingOptions = self.diskCacheWritingOptions; - config.maxCacheAge = self.maxCacheAge; - config.maxCacheSize = self.maxCacheSize; + config.maxDiskAge = self.maxDiskAge; + config.maxDiskSize = self.maxDiskSize; config.maxMemoryCost = self.maxMemoryCost; config.maxMemoryCount = self.maxMemoryCount; config.diskCacheExpireType = self.diskCacheExpireType; From 2bfdac1f60aa7b89f61c01bdcded56b9b1b23acd Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 27 Dec 2018 15:48:54 +0800 Subject: [PATCH 301/361] Update the test cases --- Tests/Tests/SDImageCacheTests.m | 4 ++-- Tests/Tests/SDWebImageTestCache.m | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index dda01837..6e4e08ff 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -195,13 +195,13 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; } - (void)test20InitialCacheSize{ - expect([[SDImageCache sharedImageCache] getSize]).to.equal(0); + expect([[SDImageCache sharedImageCache] totalDiskSize]).to.equal(0); } - (void)test21InitialDiskCount{ XCTestExpectation *expectation = [self expectationWithDescription:@"getDiskCount"]; [[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:^{ - expect([[SDImageCache sharedImageCache] getDiskCount]).to.equal(1); + expect([[SDImageCache sharedImageCache] totalDiskCount]).to.equal(1); [[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{ [expectation fulfill]; }]; diff --git a/Tests/Tests/SDWebImageTestCache.m b/Tests/Tests/SDWebImageTestCache.m index 1a92ec8f..7ef29cf7 100644 --- a/Tests/Tests/SDWebImageTestCache.m +++ b/Tests/Tests/SDWebImageTestCache.m @@ -77,7 +77,7 @@ } - (void)removeExpiredData { - NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.config.maxCacheAge]; + NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.config.maxDiskAge]; for (NSString *fileName in [self.fileManager enumeratorAtPath:self.cachePath]) { NSString *filePath = [self.cachePath stringByAppendingPathComponent:fileName]; NSDate *modificationDate = [[self.fileManager attributesOfItemAtPath:filePath error:nil] objectForKey:NSFileModificationDate]; From 2489913e950601bd7da1bb576f93b4c3f111c790 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 27 Dec 2018 16:09:34 +0800 Subject: [PATCH 302/361] Update some comments related to naming changes --- SDWebImage/SDDiskCache.h | 2 +- SDWebImage/SDDiskCache.m | 6 +++--- SDWebImage/SDImageCache.h | 2 +- SDWebImage/SDImageCacheConfig.m | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/SDWebImage/SDDiskCache.h b/SDWebImage/SDDiskCache.h index fbe893f5..626ca2e0 100644 --- a/SDWebImage/SDDiskCache.h +++ b/SDWebImage/SDDiskCache.h @@ -15,7 +15,7 @@ // All of these method are called from the same global queue to avoid blocking on main queue and thread-safe problem. But it's also recommend to ensure thread-safe yourself using lock or other ways. @required /** - Create a new disk cache based on the specified path. + Create a new disk cache based on the specified path. You can check `maxDiskSize` and `maxDiskAge` used for disk cache. @param cachePath Full path of a directory in which the cache will write data. Once initialized you should not read and write to this directory. diff --git a/SDWebImage/SDDiskCache.m b/SDWebImage/SDDiskCache.m index 33354994..21648972 100644 --- a/SDWebImage/SDDiskCache.m +++ b/SDWebImage/SDDiskCache.m @@ -172,10 +172,10 @@ // If our remaining disk cache exceeds a configured maximum size, perform a second // size-based cleanup pass. We delete the oldest files first. - NSUInteger maxCacheSize = self.config.maxDiskSize; - if (maxCacheSize > 0 && currentCacheSize > maxCacheSize) { + NSUInteger maxDiskSize = self.config.maxDiskSize; + if (maxDiskSize > 0 && currentCacheSize > maxDiskSize) { // Target half of our maximum cache size for this cleanup pass. - const NSUInteger desiredCacheSize = maxCacheSize / 2; + const NSUInteger desiredCacheSize = maxDiskSize / 2; // Sort the remaining cache files by their last modification time or last access time (oldest first). NSArray *sortedFiles = [cacheFiles keysSortedByValueWithOptions:NSSortConcurrent diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 4284cea8..bcbd3068 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -321,7 +321,7 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { #pragma mark - Cache Info /** - * Get the size used by the disk cache + * Get the total bytes size of images in the disk cache */ - (NSUInteger)totalDiskSize; diff --git a/SDWebImage/SDImageCacheConfig.m b/SDWebImage/SDImageCacheConfig.m index 831de835..40a53348 100644 --- a/SDWebImage/SDImageCacheConfig.m +++ b/SDWebImage/SDImageCacheConfig.m @@ -11,7 +11,7 @@ #import "SDDiskCache.h" static SDImageCacheConfig *_defaultCacheConfig; -static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week +static const NSInteger kDefaultCacheMaxDiskAge = 60 * 60 * 24 * 7; // 1 week @implementation SDImageCacheConfig @@ -31,7 +31,7 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week _shouldRemoveExpiredDataWhenEnterBackground = YES; _diskCacheReadingOptions = 0; _diskCacheWritingOptions = NSDataWritingAtomic; - _maxDiskAge = kDefaultCacheMaxCacheAge; + _maxDiskAge = kDefaultCacheMaxDiskAge; _maxDiskSize = 0; _diskCacheExpireType = SDImageCacheConfigExpireTypeModificationDate; _memoryCacheClass = [SDMemoryCache class]; From bb00bf1b7335f37cd537736639a4fc9ad54e9fcc Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 26 Jan 2019 18:16:22 +0800 Subject: [PATCH 303/361] Update the CHANGELOG and API diff --- CHANGELOG.md | 33 +++++++++++++++++++++++++++++ Docs/API-Diff/5.0/apidiff.html | 38 ++++++++++++++++++++++++++-------- 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 860c23e6..c923ac54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,36 @@ +## [5.0.0-beta4 - Customizable SDWebImage, on Jan 26th, 2019](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta4) +See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/milestone/15) + +#### Features +- Expose the graphics helper method for coder plugin author and fix scale issue #2523 + +#### Performances +- Decrease animated decode times when cache enable #2468 +- Remove kCGImageSourceShouldCache option when creating image source #2472 +- Add autoreleasepool to release autorelease objects in advance when using GCD #2474 + +#### Fixes +- Add protect when custom animated image class image data is nil during progressive animation check #2466 +- Fix background download #2500 + +#### Project +- Merged targets + MapKit dedicated target for Carthage installs #2476. Carthage user now does not enable MapKit support by default. +- Upgrade Xcode 10 + using xcconfig for project settings #2494 + +#### Notable Changes (from beta3) + +Behavior: + +- Move webp component (and libwebp dependency) to SDWebImage/SDWebImageWebPCoder #2469. Any user who use WebP in 5.0.0 should add [SDWebImageWebPCoder](https://github.com/SDWebImage/SDWebImageWebPCoder) to your Podfile or Cartfile instead. +- Refactory cache path about namespace && final cache directory #2535. Now the default disk cache path was moved to suitable path with the namespace. +- Use the memory bytes size, instead of pixel size to calculate the memory cost function #2568. Now the memory cost function use bytes size instead of pixels count. + +Swift Only: + +- Fix the accident changes of Swift API naming for `sd_imageDataAsFormat:` #2517 + +You can always check [5.0 migration guide](https://github.com/SDWebImage/SDWebImage/wiki/5.0-Migration-guide) for the latest information for these changes. + ## [5.0.0-beta3 - Customizable SDWebImage, on Aug 30th, 2018](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta3) See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/milestone/15) diff --git a/Docs/API-Diff/5.0/apidiff.html b/Docs/API-Diff/5.0/apidiff.html index 13c7d66c..ce82699a 100644 --- a/Docs/API-Diff/5.0/apidiff.html +++ b/Docs/API-Diff/5.0/apidiff.html @@ -227,6 +227,8 @@
Removed SDImageCache.maxMemoryCountLimit
Removed -[SDImageCache makeDiskCachePath:]
Removed -[SDImageCache addReadOnlyCachePath:]
+
Removed -[SDImageCache getSize]
+
Removed -[SDImageCache getDiskCount]
Removed -[SDImageCache cachePathForKey:inPath:]
Removed -[SDImageCache defaultCachePathForKey:]
@@ -247,6 +249,8 @@
Added -[SDImageCache queryCacheOperationForKey:options:context:done:]
Added -[SDImageCache removeImageFromMemoryForKey:]
Added -[SDImageCache removeImageFromDiskForKey:]
+
Added -[SDImageCache totalDiskSize]
+
Added -[SDImageCache totalDiskCount]
@@ -272,6 +276,13 @@
Declaration
To@property (class, nonatomic, readonly, nonnull) SDImageCache *sharedImageCache

+
Modified -[SDImageCache initWithNamespace:diskCacheDirectory:]
+ + + + +
Declaration
From- (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns diskCacheDirectory:(nonnull NSString *)directory
To- (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns diskCacheDirectory:(nullable NSString *)directory
+
Modified -[SDImageCache diskImageExistsWithKey:completion:]
@@ -309,15 +320,18 @@
Removed SDImageCacheConfig.shouldDecompressImages
+
Removed SDImageCacheConfig.maxCacheAge
+
Removed SDImageCacheConfig.maxCacheSize
Added SDImageCacheConfig.defaultCacheConfig
Added SDImageCacheConfig.shouldRemoveExpiredDataWhenEnterBackground
+
Added SDImageCacheConfig.maxDiskAge
+
Added SDImageCacheConfig.maxDiskSize
Added SDImageCacheConfig.maxMemoryCost
Added SDImageCacheConfig.maxMemoryCount
-
Added SDImageCacheConfig.namespacePrefix
Added SDImageCacheConfig.fileManager
Added SDImageCacheConfig.memoryCacheClass
Added SDImageCacheConfig.diskCacheClass
@@ -332,13 +346,6 @@
Declaration
ToNSCopying

-
Modified SDImageCacheConfig.maxCacheAge
- - - - -
Declaration
From@property (nonatomic, assign) NSInteger maxCacheAge
To@property (nonatomic, assign) NSTimeInterval maxCacheAge
-
@@ -475,6 +482,19 @@ +
+
SDImageGraphics.h
+ +
+
Added SDGraphicsGetCurrentContext()
+
Added SDGraphicsBeginImageContext()
+
Added SDGraphicsBeginImageContextWithOptions()
+
Added SDGraphicsEndImageContext()
+
Added SDGraphicsGetImageFromCurrentImageContext()
+
+ +
+
SDImageIOCoder.h
@@ -563,7 +583,6 @@
SDMemoryCache.h
-
Added SDMemoryCacheCostForImage()
Added SDMemoryCache
Added -[SDMemoryCache initWithConfig:]
Added -[SDMemoryCache objectForKey:]
@@ -1283,6 +1302,7 @@
Removed SDWebImageInternalSetImageGroupKey
Removed SDWebImageExternalCustomManagerKey
+
Removed SDInternalSetImageBlock
Removed -[UIView sd_internalSetImageWithURL:placeholderImage:options:operationKey:setImageBlock:progress:completed:]
Removed -[UIView sd_internalSetImageWithURL:placeholderImage:options:operationKey:setImageBlock:progress:completed:context:]
Removed -[UIView sd_setShowActivityIndicatorView:]
From 2864fe36193c1ca4e8b85ba48fcdbb358e65e43e Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 26 Jan 2019 18:17:35 +0800 Subject: [PATCH 304/361] Bumped version to 5.0.0-beta4 --- SDWebImage.podspec | 2 +- WebImage/Info.plist | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SDWebImage.podspec b/SDWebImage.podspec index c3abd417..05d9f157 100644 --- a/SDWebImage.podspec +++ b/SDWebImage.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'SDWebImage' - s.version = '5.0.0-beta3' + s.version = '5.0.0-beta4' s.osx.deployment_target = '10.10' s.ios.deployment_target = '8.0' diff --git a/WebImage/Info.plist b/WebImage/Info.plist index aed10d12..8cc132fb 100644 --- a/WebImage/Info.plist +++ b/WebImage/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.0.0-beta3 + 5.0.0-beta4 CFBundleSignature ???? CFBundleVersion - 5.0.0-beta3 + 5.0.0-beta4 NSPrincipalClass From df28feb99c17f58aa29491edd6c804e9f6b17073 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 28 Jan 2019 13:17:46 +0800 Subject: [PATCH 305/361] Fix the silly bug that coders manager ignore all encoding options. Which cause many features during encoding does not works --- SDWebImage/SDImageCodersManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/SDImageCodersManager.m b/SDWebImage/SDImageCodersManager.m index 7572049f..77522cd4 100644 --- a/SDWebImage/SDImageCodersManager.m +++ b/SDWebImage/SDImageCodersManager.m @@ -117,7 +117,7 @@ SD_UNLOCK(self.codersLock); for (id coder in coders.reverseObjectEnumerator) { if ([coder canEncodeToFormat:format]) { - return [coder encodedDataWithImage:image format:format options:nil]; + return [coder encodedDataWithImage:image format:format options:options]; } } return nil; From e303b7aed6dc48edcda016135132a3d7bfcb62dd Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 28 Jan 2019 13:57:55 +0800 Subject: [PATCH 306/361] Update the test case to ensure the encoding options work --- SDWebImage/SDImageAPNGCoder.m | 3 ++- SDWebImage/SDImageGIFCoder.m | 3 ++- Tests/Tests/SDCategoriesTests.m | 7 +++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDImageAPNGCoder.m b/SDWebImage/SDImageAPNGCoder.m index 64384122..07c03f66 100644 --- a/SDWebImage/SDImageAPNGCoder.m +++ b/SDWebImage/SDImageAPNGCoder.m @@ -208,7 +208,8 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; if (encodeFirstFrame || frames.count == 0) { // for static single PNG images - CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); + CGImageRef imageRef = frames.firstObject.image.CGImage ?: image.CGImage; + CGImageDestinationAddImage(imageDestination, imageRef, (__bridge CFDictionaryRef)properties); } else { // for animated APNG images NSUInteger loopCount = image.sd_imageLoopCount; diff --git a/SDWebImage/SDImageGIFCoder.m b/SDWebImage/SDImageGIFCoder.m index 2bea5b94..f00188b7 100644 --- a/SDWebImage/SDImageGIFCoder.m +++ b/SDWebImage/SDImageGIFCoder.m @@ -293,7 +293,8 @@ BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; if (encodeFirstFrame || frames.count == 0) { // for static single GIF images - CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); + CGImageRef imageRef = frames.firstObject.image.CGImage ?: image.CGImage; + CGImageDestinationAddImage(imageDestination, imageRef, (__bridge CFDictionaryRef)properties); } else { // for animated GIF images NSUInteger loopCount = image.sd_imageLoopCount; diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m index 08415834..3364fabb 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDCategoriesTests.m @@ -39,6 +39,12 @@ // Test image encode PNG data = [image sd_imageDataAsFormat:SDImageFormatPNG]; expect(data).notTo.beNil(); + // Test image encode JPEG with compressionQuality + NSData *jpegData1 = [image sd_imageDataAsFormat:SDImageFormatJPEG compressionQuality:1]; + NSData *jpegData2 = [image sd_imageDataAsFormat:SDImageFormatJPEG compressionQuality:0.5]; + expect(jpegData1).notTo.beNil(); + expect(jpegData2).notTo.beNil(); + expect(jpegData1.length).notTo.equal(jpegData2.length); } - (void)test03UIImageGIFCategory { @@ -49,6 +55,7 @@ NSData *data = [NSData dataWithContentsOfFile:[self testGIFPath]]; image = [UIImage sd_imageWithGIFData:data]; expect(image).notTo.beNil(); + expect(image.sd_isAnimated).beTruthy(); } #pragma mark - Helper From 403820f89e00bb96aea9899529acbc547dc132ea Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Tue, 29 Jan 2019 22:07:43 +0800 Subject: [PATCH 307/361] Remove unnecessary CGImage check when encode first frame --- SDWebImage/SDImageAPNGCoder.m | 3 +-- SDWebImage/SDImageGIFCoder.m | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/SDWebImage/SDImageAPNGCoder.m b/SDWebImage/SDImageAPNGCoder.m index 07c03f66..64384122 100644 --- a/SDWebImage/SDImageAPNGCoder.m +++ b/SDWebImage/SDImageAPNGCoder.m @@ -208,8 +208,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; if (encodeFirstFrame || frames.count == 0) { // for static single PNG images - CGImageRef imageRef = frames.firstObject.image.CGImage ?: image.CGImage; - CGImageDestinationAddImage(imageDestination, imageRef, (__bridge CFDictionaryRef)properties); + CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); } else { // for animated APNG images NSUInteger loopCount = image.sd_imageLoopCount; diff --git a/SDWebImage/SDImageGIFCoder.m b/SDWebImage/SDImageGIFCoder.m index f00188b7..2bea5b94 100644 --- a/SDWebImage/SDImageGIFCoder.m +++ b/SDWebImage/SDImageGIFCoder.m @@ -293,8 +293,7 @@ BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; if (encodeFirstFrame || frames.count == 0) { // for static single GIF images - CGImageRef imageRef = frames.firstObject.image.CGImage ?: image.CGImage; - CGImageDestinationAddImage(imageDestination, imageRef, (__bridge CFDictionaryRef)properties); + CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); } else { // for animated GIF images NSUInteger loopCount = image.sd_imageLoopCount; From 537affb9af4d42696902444830040d47bc7b4a7c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 31 Jan 2019 19:10:57 +0800 Subject: [PATCH 308/361] Bumped version to 5.0.0-beta5 --- SDWebImage.podspec | 2 +- WebImage/Info.plist | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SDWebImage.podspec b/SDWebImage.podspec index 047d236e..265a4b9b 100644 --- a/SDWebImage.podspec +++ b/SDWebImage.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'SDWebImage' - s.version = '5.0.0-beta4' + s.version = '5.0.0-beta5' s.osx.deployment_target = '10.10' s.ios.deployment_target = '8.0' diff --git a/WebImage/Info.plist b/WebImage/Info.plist index 8cc132fb..da8b600c 100644 --- a/WebImage/Info.plist +++ b/WebImage/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.0.0-beta4 + 5.0.0-beta5 CFBundleSignature ???? CFBundleVersion - 5.0.0-beta4 + 5.0.0-beta5 NSPrincipalClass From 2ce3b706c8c4ebad48d7458719b976196a924a31 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 3 Mar 2019 16:52:44 +0800 Subject: [PATCH 309/361] Fix the issue that SDWebImagePrefetch in 5.x, will submit all prefetch URLs to manager without any limit, which cause the disk cache query pending until all finished Because they are implementation details, we can not always assume the cache and downloader use a load balancing algorithm --- SDWebImage.xcodeproj/project.pbxproj | 12 ++++ SDWebImage/SDAsyncBlockOperation.h | 20 +++++++ SDWebImage/SDAsyncBlockOperation.m | 55 ++++++++++++++++++ SDWebImage/SDWebImagePrefetcher.h | 5 ++ SDWebImage/SDWebImagePrefetcher.m | 86 +++++++++++++++++----------- 5 files changed, 145 insertions(+), 33 deletions(-) create mode 100644 SDWebImage/SDAsyncBlockOperation.h create mode 100644 SDWebImage/SDAsyncBlockOperation.m diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 6099f9b8..2cb8cf80 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -87,6 +87,10 @@ 3290FA061FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3290FA0A1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; 3290FA0C1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; + 3299C4EE222BC3FD00DABA0F /* SDAsyncBlockOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 3299C4EC222BC3FD00DABA0F /* SDAsyncBlockOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3299C4EF222BC3FD00DABA0F /* SDAsyncBlockOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 3299C4EC222BC3FD00DABA0F /* SDAsyncBlockOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3299C4F0222BC3FD00DABA0F /* SDAsyncBlockOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3299C4ED222BC3FD00DABA0F /* SDAsyncBlockOperation.m */; }; + 3299C4F1222BC3FD00DABA0F /* SDAsyncBlockOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3299C4ED222BC3FD00DABA0F /* SDAsyncBlockOperation.m */; }; 329A18591FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; 329A185B1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; 329A185F1FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; @@ -267,6 +271,8 @@ 328BB6C02082581100760D6C /* SDMemoryCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDMemoryCache.m; sourceTree = ""; }; 3290FA021FA478AF0047D20C /* SDImageFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageFrame.h; sourceTree = ""; }; 3290FA031FA478AF0047D20C /* SDImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageFrame.m; sourceTree = ""; }; + 3299C4EC222BC3FD00DABA0F /* SDAsyncBlockOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDAsyncBlockOperation.h; sourceTree = ""; }; + 3299C4ED222BC3FD00DABA0F /* SDAsyncBlockOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDAsyncBlockOperation.m; sourceTree = ""; }; 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Metadata.h"; sourceTree = ""; }; 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Metadata.m"; sourceTree = ""; }; 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderConfig.h; sourceTree = ""; }; @@ -425,6 +431,8 @@ children = ( 53922D91148C56230056699D /* SDWebImagePrefetcher.h */, 53922D92148C56230056699D /* SDWebImagePrefetcher.m */, + 3299C4EC222BC3FD00DABA0F /* SDAsyncBlockOperation.h */, + 3299C4ED222BC3FD00DABA0F /* SDAsyncBlockOperation.m */, ); name = Prefetcher; sourceTree = ""; @@ -633,6 +641,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 3299C4EF222BC3FD00DABA0F /* SDAsyncBlockOperation.h in Headers */, 32D122202080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 3257EAFA21898AED0097B271 /* SDImageGraphics.h in Headers */, @@ -690,6 +699,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 3299C4EE222BC3FD00DABA0F /* SDAsyncBlockOperation.h in Headers */, 32CF1C071FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, 32F7C0842030719600873181 /* UIImage+Transform.h in Headers */, 3257EAF921898AED0097B271 /* SDImageGraphics.h in Headers */, @@ -896,6 +906,7 @@ 32F7C0772030114C00873181 /* SDImageTransformer.m in Sources */, 3237F9E820161AE000A88143 /* NSImage+Compatibility.m in Sources */, 32C0FDE92013426C001B8F2D /* SDWebImageIndicator.m in Sources */, + 3299C4F1222BC3FD00DABA0F /* SDAsyncBlockOperation.m in Sources */, 32F21B5920788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 321B37952083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, 4A2CAE361AB4BB7500B6BC39 /* UIImageView+WebCache.m in Sources */, @@ -951,6 +962,7 @@ 32F7C0752030114C00873181 /* SDImageTransformer.m in Sources */, 3237F9EB20161AE000A88143 /* NSImage+Compatibility.m in Sources */, 32C0FDE72013426C001B8F2D /* SDWebImageIndicator.m in Sources */, + 3299C4F0222BC3FD00DABA0F /* SDAsyncBlockOperation.m in Sources */, 32F21B5720788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 5376130B155AD0D5005750A4 /* SDWebImageDownloader.m in Sources */, 321B37932083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, diff --git a/SDWebImage/SDAsyncBlockOperation.h b/SDWebImage/SDAsyncBlockOperation.h new file mode 100644 index 00000000..ecc68be8 --- /dev/null +++ b/SDWebImage/SDAsyncBlockOperation.h @@ -0,0 +1,20 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +@class SDAsyncBlockOperation; +typedef void (^SDAsyncBlock)(SDAsyncBlockOperation * __nonnull asyncOperation); + +@interface SDAsyncBlockOperation : NSOperation + +- (nonnull instancetype)initWithBlock:(nonnull SDAsyncBlock)block; ++ (nonnull instancetype)blockOperationWithBlock:(nonnull SDAsyncBlock)block; +- (void)complete; + +@end diff --git a/SDWebImage/SDAsyncBlockOperation.m b/SDWebImage/SDAsyncBlockOperation.m new file mode 100644 index 00000000..5e3e0fe5 --- /dev/null +++ b/SDWebImage/SDAsyncBlockOperation.m @@ -0,0 +1,55 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDAsyncBlockOperation.h" + +@interface SDAsyncBlockOperation () + +@property (nonatomic, assign) BOOL isExecuting; +@property (nonatomic, assign) BOOL isFinished; +@property (nonatomic, copy, nonnull) SDAsyncBlock executionBlock; + +@end + +@implementation SDAsyncBlockOperation + +- (nonnull instancetype)initWithBlock:(nonnull SDAsyncBlock)block { + self = [super init]; + if (self) { + self.executionBlock = block; + } + return self; +} + ++ (nonnull instancetype)blockOperationWithBlock:(nonnull SDAsyncBlock)block { + SDAsyncBlockOperation *operation = [[SDAsyncBlockOperation alloc] initWithBlock:block]; + return operation; +} + +- (void)start { + [self willChangeValueForKey:@"isExecuting"]; + self.isExecuting = YES; + [self didChangeValueForKey:@"isExecuting"]; + + if (self.executionBlock) { + self.executionBlock(self); + } else { + [self complete]; + } +} + +- (void)complete { + [self willChangeValueForKey:@"isExecuting"]; + [self willChangeValueForKey:@"isFinished"]; + self.isExecuting = NO; + self.isFinished = YES; + [self didChangeValueForKey:@"isExecuting"]; + [self didChangeValueForKey:@"isFinished"]; +} + +@end diff --git a/SDWebImage/SDWebImagePrefetcher.h b/SDWebImage/SDWebImagePrefetcher.h index 5c3bb8c0..44c11d5a 100644 --- a/SDWebImage/SDWebImagePrefetcher.h +++ b/SDWebImage/SDWebImagePrefetcher.h @@ -63,6 +63,11 @@ typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, */ @property (strong, nonatomic, readonly, nonnull) SDWebImageManager *manager; +/** + * Maximum number of URLs to prefetch at the same time. Defaults to 3. + */ +@property (nonatomic, assign) NSUInteger maxConcurrentPrefetchCount; + /** * The options for prefetcher. Defaults to SDWebImageLowPriority. */ diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index 035354eb..73dda304 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -7,6 +7,7 @@ */ #import "SDWebImagePrefetcher.h" +#import "SDAsyncBlockOperation.h" #import @interface SDWebImagePrefetchToken () { @@ -32,6 +33,7 @@ @property (strong, nonatomic, nonnull) SDWebImageManager *manager; @property (strong, atomic, nonnull) NSMutableSet *runningTokens; +@property (strong, nonatomic, nonnull) NSOperationQueue *prefetchQueue; @end @@ -56,10 +58,20 @@ _runningTokens = [NSMutableSet set]; _options = SDWebImageLowPriority; _delegateQueue = dispatch_get_main_queue(); + _prefetchQueue = [NSOperationQueue new]; + self.maxConcurrentPrefetchCount = 3; } return self; } +- (void)setMaxConcurrentPrefetchCount:(NSUInteger)maxConcurrentPrefetchCount { + self.prefetchQueue.maxConcurrentOperationCount = maxConcurrentPrefetchCount; +} + +- (NSUInteger)maxConcurrentPrefetchCount { + return self.prefetchQueue.maxConcurrentOperationCount; +} + #pragma mark - Prefetch - (nullable SDWebImagePrefetchToken *)prefetchURLs:(nullable NSArray *)urls { return [self prefetchURLs:urls progress:nil completed:nil]; @@ -85,43 +97,51 @@ token.progressBlock = progressBlock; token.completionBlock = completionBlock; [self addRunningToken:token]; - - NSPointerArray *operations = token.operations; - for (NSURL *url in urls) { - __weak typeof(self) wself = self; - id operation = [self.manager loadImageWithURL:url options:self.options context:self.context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { - __strong typeof(wself) sself = wself; - if (!sself) { - return; - } - if (!finished) { - return; - } - atomic_fetch_add_explicit(&(token->_finishedCount), 1, memory_order_relaxed); - if (error) { - // Add last failed - atomic_fetch_add_explicit(&(token->_skippedCount), 1, memory_order_relaxed); - } - - // Current operation finished - [sself callProgressBlockForToken:token imageURL:imageURL]; - - if (atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed) == token->_totalCount) { - // All finished - if (!atomic_flag_test_and_set_explicit(&(token->_isAllFinished), memory_order_relaxed)) { - [sself callCompletionBlockForToken:token]; - [sself removeRunningToken:token]; - } - } - }]; - @synchronized (token) { - [operations addPointer:(__bridge void *)operation]; - } - } + [self startPrefetchWithToken:token]; return token; } +- (void)startPrefetchWithToken:(SDWebImagePrefetchToken * _Nonnull)token { + NSPointerArray *operations = token.operations; + for (NSURL *url in token.urls) { + __weak typeof(self) wself = self; + SDAsyncBlockOperation *prefetchOperation = [SDAsyncBlockOperation blockOperationWithBlock:^(SDAsyncBlockOperation * _Nonnull asyncOperation) { + id operation = [self.manager loadImageWithURL:url options:self.options context:self.context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + __strong typeof(wself) sself = wself; + if (!sself) { + return; + } + if (!finished) { + return; + } + [asyncOperation complete]; + + atomic_fetch_add_explicit(&(token->_finishedCount), 1, memory_order_relaxed); + if (error) { + // Add last failed + atomic_fetch_add_explicit(&(token->_skippedCount), 1, memory_order_relaxed); + } + + // Current operation finished + [sself callProgressBlockForToken:token imageURL:imageURL]; + + if (atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed) == token->_totalCount) { + // All finished + if (!atomic_flag_test_and_set_explicit(&(token->_isAllFinished), memory_order_relaxed)) { + [sself callCompletionBlockForToken:token]; + [sself removeRunningToken:token]; + } + } + }]; + @synchronized (token) { + [operations addPointer:(__bridge void *)operation]; + } + }]; + [self.prefetchQueue addOperation:prefetchOperation]; + } +} + #pragma mark - Cancel - (void)cancelPrefetching { @synchronized(self.runningTokens) { From cf0738abd98714c1062dfc7d04771f51a5a50918 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 6 Mar 2019 13:05:22 +0800 Subject: [PATCH 310/361] Move the SDAsyncBlockOperation into the private header folder, this class is only used inside framework --- SDWebImage.podspec | 3 +- SDWebImage.xcodeproj/project.pbxproj | 32 ++++++++++++------- .../{ => Private}/SDAsyncBlockOperation.h | 0 .../{ => Private}/SDAsyncBlockOperation.m | 0 4 files changed, 22 insertions(+), 13 deletions(-) rename SDWebImage/{ => Private}/SDAsyncBlockOperation.h (100%) rename SDWebImage/{ => Private}/SDAsyncBlockOperation.m (100%) diff --git a/SDWebImage.podspec b/SDWebImage.podspec index 265a4b9b..4ed29a05 100644 --- a/SDWebImage.podspec +++ b/SDWebImage.podspec @@ -28,8 +28,9 @@ Pod::Spec.new do |s| s.default_subspec = 'Core' s.subspec 'Core' do |core| - core.source_files = 'SDWebImage/*.{h,m}', 'WebImage/SDWebImage.h' + core.source_files = 'SDWebImage/*.{h,m}', 'WebImage/SDWebImage.h', 'SDWebImage/Private/*.{h,m}' core.exclude_files = 'SDWebImage/MapKit/*.{h,m}' + core.private_header_files = 'SDWebImage/Private/*.h' end s.subspec 'MapKit' do |mk| diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 2cb8cf80..52d8a6cb 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -87,14 +87,14 @@ 3290FA061FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3290FA0A1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; 3290FA0C1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; - 3299C4EE222BC3FD00DABA0F /* SDAsyncBlockOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 3299C4EC222BC3FD00DABA0F /* SDAsyncBlockOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3299C4EF222BC3FD00DABA0F /* SDAsyncBlockOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 3299C4EC222BC3FD00DABA0F /* SDAsyncBlockOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3299C4F0222BC3FD00DABA0F /* SDAsyncBlockOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3299C4ED222BC3FD00DABA0F /* SDAsyncBlockOperation.m */; }; - 3299C4F1222BC3FD00DABA0F /* SDAsyncBlockOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3299C4ED222BC3FD00DABA0F /* SDAsyncBlockOperation.m */; }; 329A18591FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; 329A185B1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; 329A185F1FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; 329A18611FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; + 32B5CC60222F89C2005EB74E /* SDAsyncBlockOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B5CC5E222F89C2005EB74E /* SDAsyncBlockOperation.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 32B5CC61222F89C2005EB74E /* SDAsyncBlockOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B5CC5F222F89C2005EB74E /* SDAsyncBlockOperation.m */; }; + 32B5CC62222F89F6005EB74E /* SDAsyncBlockOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B5CC5E222F89C2005EB74E /* SDAsyncBlockOperation.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 32B5CC63222F8B70005EB74E /* SDAsyncBlockOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B5CC5F222F89C2005EB74E /* SDAsyncBlockOperation.m */; }; 32B9B537206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32B9B53D206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */; }; @@ -271,10 +271,10 @@ 328BB6C02082581100760D6C /* SDMemoryCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDMemoryCache.m; sourceTree = ""; }; 3290FA021FA478AF0047D20C /* SDImageFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageFrame.h; sourceTree = ""; }; 3290FA031FA478AF0047D20C /* SDImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageFrame.m; sourceTree = ""; }; - 3299C4EC222BC3FD00DABA0F /* SDAsyncBlockOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDAsyncBlockOperation.h; sourceTree = ""; }; - 3299C4ED222BC3FD00DABA0F /* SDAsyncBlockOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDAsyncBlockOperation.m; sourceTree = ""; }; 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Metadata.h"; sourceTree = ""; }; 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Metadata.m"; sourceTree = ""; }; + 32B5CC5E222F89C2005EB74E /* SDAsyncBlockOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDAsyncBlockOperation.h; sourceTree = ""; }; + 32B5CC5F222F89C2005EB74E /* SDAsyncBlockOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDAsyncBlockOperation.m; sourceTree = ""; }; 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderConfig.h; sourceTree = ""; }; 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderConfig.m; sourceTree = ""; }; 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageIndicator.h; sourceTree = ""; }; @@ -431,8 +431,6 @@ children = ( 53922D91148C56230056699D /* SDWebImagePrefetcher.h */, 53922D92148C56230056699D /* SDWebImagePrefetcher.m */, - 3299C4EC222BC3FD00DABA0F /* SDAsyncBlockOperation.h */, - 3299C4ED222BC3FD00DABA0F /* SDAsyncBlockOperation.m */, ); name = Prefetcher; sourceTree = ""; @@ -446,6 +444,15 @@ name = Transformer; sourceTree = ""; }; + 32B5CC5D222F89C2005EB74E /* Private */ = { + isa = PBXGroup; + children = ( + 32B5CC5E222F89C2005EB74E /* SDAsyncBlockOperation.h */, + 32B5CC5F222F89C2005EB74E /* SDAsyncBlockOperation.m */, + ); + path = Private; + sourceTree = ""; + }; 32FDE8792088871B008D7530 /* MapKit */ = { isa = PBXGroup; children = ( @@ -538,6 +545,7 @@ 53922DAC148C56DD0056699D /* Utils */, 53922DA9148C562D0056699D /* Categories */, 4369C2851D9811BB007E863A /* WebCache Categories */, + 32B5CC5D222F89C2005EB74E /* Private */, 32FDE8792088871B008D7530 /* MapKit */, ); path = SDWebImage; @@ -641,7 +649,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 3299C4EF222BC3FD00DABA0F /* SDAsyncBlockOperation.h in Headers */, + 32B5CC60222F89C2005EB74E /* SDAsyncBlockOperation.h in Headers */, 32D122202080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 3257EAFA21898AED0097B271 /* SDImageGraphics.h in Headers */, @@ -699,7 +707,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 3299C4EE222BC3FD00DABA0F /* SDAsyncBlockOperation.h in Headers */, + 32B5CC62222F89F6005EB74E /* SDAsyncBlockOperation.h in Headers */, 32CF1C071FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, 32F7C0842030719600873181 /* UIImage+Transform.h in Headers */, 3257EAF921898AED0097B271 /* SDImageGraphics.h in Headers */, @@ -906,7 +914,7 @@ 32F7C0772030114C00873181 /* SDImageTransformer.m in Sources */, 3237F9E820161AE000A88143 /* NSImage+Compatibility.m in Sources */, 32C0FDE92013426C001B8F2D /* SDWebImageIndicator.m in Sources */, - 3299C4F1222BC3FD00DABA0F /* SDAsyncBlockOperation.m in Sources */, + 32B5CC61222F89C2005EB74E /* SDAsyncBlockOperation.m in Sources */, 32F21B5920788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 321B37952083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, 4A2CAE361AB4BB7500B6BC39 /* UIImageView+WebCache.m in Sources */, @@ -962,7 +970,7 @@ 32F7C0752030114C00873181 /* SDImageTransformer.m in Sources */, 3237F9EB20161AE000A88143 /* NSImage+Compatibility.m in Sources */, 32C0FDE72013426C001B8F2D /* SDWebImageIndicator.m in Sources */, - 3299C4F0222BC3FD00DABA0F /* SDAsyncBlockOperation.m in Sources */, + 32B5CC63222F8B70005EB74E /* SDAsyncBlockOperation.m in Sources */, 32F21B5720788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 5376130B155AD0D5005750A4 /* SDWebImageDownloader.m in Sources */, 321B37932083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, diff --git a/SDWebImage/SDAsyncBlockOperation.h b/SDWebImage/Private/SDAsyncBlockOperation.h similarity index 100% rename from SDWebImage/SDAsyncBlockOperation.h rename to SDWebImage/Private/SDAsyncBlockOperation.h diff --git a/SDWebImage/SDAsyncBlockOperation.m b/SDWebImage/Private/SDAsyncBlockOperation.m similarity index 100% rename from SDWebImage/SDAsyncBlockOperation.m rename to SDWebImage/Private/SDAsyncBlockOperation.m From 6bab2de69a98308595a02bda9374be896e4a51f6 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 9 Mar 2019 15:19:25 +0800 Subject: [PATCH 311/361] Move some internal classes into private header files, make it easy to maintain the code --- .../SDWebImage Demo.xcodeproj/project.pbxproj | 16 +- SDWebImage.xcodeproj/project.pbxproj | 72 ++++++++ .../Private/NSBezierPath+RoundedCorners.h | 24 +++ .../Private/NSBezierPath+RoundedCorners.m | 42 +++++ SDWebImage/Private/SDImageAPNGCoder+Private.h | 17 ++ SDWebImage/Private/SDImageAssetManager.h | 23 +++ SDWebImage/Private/SDImageAssetManager.m | 157 +++++++++++++++++ .../Private/SDImageCachesManagerOperation.h | 21 +++ .../Private/SDImageCachesManagerOperation.m | 60 +++++++ SDWebImage/Private/SDImageGIFCoder+Private.h | 16 ++ SDWebImage/Private/SDWeakProxy.h | 19 ++ SDWebImage/Private/SDWeakProxy.m | 79 +++++++++ SDWebImage/Private/UIColor+HexString.h | 18 ++ SDWebImage/Private/UIColor+HexString.m | 42 +++++ SDWebImage/SDAnimatedImage.m | 164 +----------------- SDWebImage/SDAnimatedImageRep.m | 17 +- SDWebImage/SDAnimatedImageView.m | 80 +-------- SDWebImage/SDImageCachesManager.m | 63 +------ SDWebImage/SDImageTransformer.m | 43 +---- SDWebImage/UIImage+Transform.m | 41 +---- .../project.pbxproj | 8 +- 21 files changed, 609 insertions(+), 413 deletions(-) create mode 100644 SDWebImage/Private/NSBezierPath+RoundedCorners.h create mode 100644 SDWebImage/Private/NSBezierPath+RoundedCorners.m create mode 100644 SDWebImage/Private/SDImageAPNGCoder+Private.h create mode 100644 SDWebImage/Private/SDImageAssetManager.h create mode 100644 SDWebImage/Private/SDImageAssetManager.m create mode 100644 SDWebImage/Private/SDImageCachesManagerOperation.h create mode 100644 SDWebImage/Private/SDImageCachesManagerOperation.m create mode 100644 SDWebImage/Private/SDImageGIFCoder+Private.h create mode 100644 SDWebImage/Private/SDWeakProxy.h create mode 100644 SDWebImage/Private/SDWeakProxy.m create mode 100644 SDWebImage/Private/UIColor+HexString.h create mode 100644 SDWebImage/Private/UIColor+HexString.m diff --git a/Examples/SDWebImage Demo.xcodeproj/project.pbxproj b/Examples/SDWebImage Demo.xcodeproj/project.pbxproj index 977ec945..5f85d8bd 100644 --- a/Examples/SDWebImage Demo.xcodeproj/project.pbxproj +++ b/Examples/SDWebImage Demo.xcodeproj/project.pbxproj @@ -634,7 +634,7 @@ files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo-frameworks.sh", + "${PODS_ROOT}/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo-frameworks.sh", "${BUILT_PRODUCTS_DIR}/SDWebImage-macOS/SDWebImage.framework", "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder-macOS/SDWebImageWebPCoder.framework", "${BUILT_PRODUCTS_DIR}/libwebp-macOS/libwebp.framework", @@ -647,7 +647,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SDWebImage OSX Demo/Pods-SDWebImage OSX Demo-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 8425DD76050A8A49F8DAF736 /* [CP] Embed Pods Frameworks */ = { @@ -656,7 +656,7 @@ files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo-frameworks.sh", + "${PODS_ROOT}/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo-frameworks.sh", "${BUILT_PRODUCTS_DIR}/SDWebImage-iOS/SDWebImage.framework", "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder-iOS/SDWebImageWebPCoder.framework", "${BUILT_PRODUCTS_DIR}/libwebp-iOS/libwebp.framework", @@ -669,7 +669,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SDWebImage iOS Demo/Pods-SDWebImage iOS Demo-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 85F5B7F46D00990FBEBF0377 /* [CP] Embed Pods Frameworks */ = { @@ -678,7 +678,7 @@ files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension-frameworks.sh", + "${PODS_ROOT}/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension-frameworks.sh", "${BUILT_PRODUCTS_DIR}/SDWebImage-watchOS/SDWebImage.framework", "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder-watchOS/SDWebImageWebPCoder.framework", "${BUILT_PRODUCTS_DIR}/libwebp-watchOS/libwebp.framework", @@ -691,7 +691,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; A50199B809E737E017D7DF1C /* [CP] Check Pods Manifest.lock */ = { @@ -772,7 +772,7 @@ files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo-frameworks.sh", + "${PODS_ROOT}/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo-frameworks.sh", "${BUILT_PRODUCTS_DIR}/SDWebImage-tvOS/SDWebImage.framework", "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder-tvOS/SDWebImageWebPCoder.framework", "${BUILT_PRODUCTS_DIR}/libwebp-tvOS/libwebp.framework", @@ -785,7 +785,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SDWebImage TV Demo/Pods-SDWebImage TV Demo-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 52d8a6cb..4609fadf 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -63,6 +63,30 @@ 3257EAFC21898AED0097B271 /* SDImageGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3257EAF821898AED0097B271 /* SDImageGraphics.m */; }; 3257EAFD21898AED0097B271 /* SDImageGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3257EAF821898AED0097B271 /* SDImageGraphics.m */; }; 3257EAFE21898AED0097B271 /* SDImageGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3257EAF821898AED0097B271 /* SDImageGraphics.m */; }; + 325C460222339330004CAE11 /* SDImageAssetManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C460022339330004CAE11 /* SDImageAssetManager.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C460322339330004CAE11 /* SDImageAssetManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C460022339330004CAE11 /* SDImageAssetManager.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C460422339330004CAE11 /* SDImageAssetManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C460122339330004CAE11 /* SDImageAssetManager.m */; }; + 325C460522339330004CAE11 /* SDImageAssetManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C460122339330004CAE11 /* SDImageAssetManager.m */; }; + 325C460822339426004CAE11 /* SDWeakProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C460622339426004CAE11 /* SDWeakProxy.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C460922339426004CAE11 /* SDWeakProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C460622339426004CAE11 /* SDWeakProxy.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C460A22339426004CAE11 /* SDWeakProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C460722339426004CAE11 /* SDWeakProxy.m */; }; + 325C460B22339426004CAE11 /* SDWeakProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C460722339426004CAE11 /* SDWeakProxy.m */; }; + 325C460E223394D8004CAE11 /* SDImageCachesManagerOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C460C223394D8004CAE11 /* SDImageCachesManagerOperation.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C460F223394D8004CAE11 /* SDImageCachesManagerOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C460C223394D8004CAE11 /* SDImageCachesManagerOperation.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C4610223394D8004CAE11 /* SDImageCachesManagerOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C460D223394D8004CAE11 /* SDImageCachesManagerOperation.m */; }; + 325C4611223394D8004CAE11 /* SDImageCachesManagerOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C460D223394D8004CAE11 /* SDImageCachesManagerOperation.m */; }; + 325C4614223399F7004CAE11 /* SDImageGIFCoder+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C4612223399F7004CAE11 /* SDImageGIFCoder+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C4615223399F7004CAE11 /* SDImageGIFCoder+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C4612223399F7004CAE11 /* SDImageGIFCoder+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C461A22339B5F004CAE11 /* SDImageAPNGCoder+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C461822339B5F004CAE11 /* SDImageAPNGCoder+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C461B22339B5F004CAE11 /* SDImageAPNGCoder+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C461822339B5F004CAE11 /* SDImageAPNGCoder+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C46202233A02E004CAE11 /* UIColor+HexString.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C461E2233A02E004CAE11 /* UIColor+HexString.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C46212233A02E004CAE11 /* UIColor+HexString.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C461E2233A02E004CAE11 /* UIColor+HexString.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C46222233A02E004CAE11 /* UIColor+HexString.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C461F2233A02E004CAE11 /* UIColor+HexString.m */; }; + 325C46232233A02E004CAE11 /* UIColor+HexString.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C461F2233A02E004CAE11 /* UIColor+HexString.m */; }; + 325C46262233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C46242233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C46272233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C46242233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C46282233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C46252233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m */; }; + 325C46292233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C46252233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m */; }; 327054D4206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 327054D6206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 327054DA206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; }; @@ -259,6 +283,18 @@ 325312C7200F09910046BF1E /* SDWebImageTransition.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransition.m; sourceTree = ""; }; 3257EAF721898AED0097B271 /* SDImageGraphics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageGraphics.h; sourceTree = ""; }; 3257EAF821898AED0097B271 /* SDImageGraphics.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageGraphics.m; sourceTree = ""; }; + 325C460022339330004CAE11 /* SDImageAssetManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageAssetManager.h; sourceTree = ""; }; + 325C460122339330004CAE11 /* SDImageAssetManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageAssetManager.m; sourceTree = ""; }; + 325C460622339426004CAE11 /* SDWeakProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWeakProxy.h; sourceTree = ""; }; + 325C460722339426004CAE11 /* SDWeakProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWeakProxy.m; sourceTree = ""; }; + 325C460C223394D8004CAE11 /* SDImageCachesManagerOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageCachesManagerOperation.h; sourceTree = ""; }; + 325C460D223394D8004CAE11 /* SDImageCachesManagerOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageCachesManagerOperation.m; sourceTree = ""; }; + 325C4612223399F7004CAE11 /* SDImageGIFCoder+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SDImageGIFCoder+Private.h"; sourceTree = ""; }; + 325C461822339B5F004CAE11 /* SDImageAPNGCoder+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SDImageAPNGCoder+Private.h"; sourceTree = ""; }; + 325C461E2233A02E004CAE11 /* UIColor+HexString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIColor+HexString.h"; sourceTree = ""; }; + 325C461F2233A02E004CAE11 /* UIColor+HexString.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIColor+HexString.m"; sourceTree = ""; }; + 325C46242233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSBezierPath+RoundedCorners.h"; sourceTree = ""; }; + 325C46252233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSBezierPath+RoundedCorners.m"; sourceTree = ""; }; 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageAPNGCoder.h; sourceTree = ""; }; 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageAPNGCoder.m; sourceTree = ""; }; 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCacheKeyFilter.h; sourceTree = ""; }; @@ -449,6 +485,18 @@ children = ( 32B5CC5E222F89C2005EB74E /* SDAsyncBlockOperation.h */, 32B5CC5F222F89C2005EB74E /* SDAsyncBlockOperation.m */, + 325C460622339426004CAE11 /* SDWeakProxy.h */, + 325C460722339426004CAE11 /* SDWeakProxy.m */, + 325C460022339330004CAE11 /* SDImageAssetManager.h */, + 325C460122339330004CAE11 /* SDImageAssetManager.m */, + 325C460C223394D8004CAE11 /* SDImageCachesManagerOperation.h */, + 325C460D223394D8004CAE11 /* SDImageCachesManagerOperation.m */, + 325C4612223399F7004CAE11 /* SDImageGIFCoder+Private.h */, + 325C461822339B5F004CAE11 /* SDImageAPNGCoder+Private.h */, + 325C461E2233A02E004CAE11 /* UIColor+HexString.h */, + 325C461F2233A02E004CAE11 /* UIColor+HexString.m */, + 325C46242233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h */, + 325C46252233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m */, ); path = Private; sourceTree = ""; @@ -655,12 +703,14 @@ 3257EAFA21898AED0097B271 /* SDImageGraphics.h in Headers */, 32D3CDD121DDE87300C4DB49 /* UIImage+MemoryCacheCost.h in Headers */, 328BB6AC2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, + 325C46272233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h in Headers */, 321B378F2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, 329A185B1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, 4369C2791D9807EC007E863A /* UIView+WebCache.h in Headers */, 32F21B5320788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 321E60961F38E8ED00405457 /* SDImageIOCoder.h in Headers */, 4A2CAE041AB4BB5400B6BC39 /* SDWebImage.h in Headers */, + 325C460322339330004CAE11 /* SDImageAssetManager.h in Headers */, 327054D6206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, 80B6DF842142B44600BCB334 /* NSButton+WebCache.h in Headers */, 43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, @@ -678,12 +728,16 @@ 4A2CAE2B1AB4BB7500B6BC39 /* UIButton+WebCache.h in Headers */, 4A2CAE251AB4BB7000B6BC39 /* SDWebImagePrefetcher.h in Headers */, 328BB6CF2082581100760D6C /* SDMemoryCache.h in Headers */, + 325C460F223394D8004CAE11 /* SDImageCachesManagerOperation.h in Headers */, + 325C461B22339B5F004CAE11 /* SDImageAPNGCoder+Private.h in Headers */, 321E60881F38E8C800405457 /* SDImageCoder.h in Headers */, 4A2CAE371AB4BB7500B6BC39 /* UIView+WebCacheOperation.h in Headers */, 321B37832083290E00C0EA77 /* SDImageLoader.h in Headers */, 32484777201775F600AF9E5A /* SDAnimatedImage.h in Headers */, + 325C460922339426004CAE11 /* SDWeakProxy.h in Headers */, 80B6DF812142B43B00BCB334 /* SDAnimatedImageRep.h in Headers */, 4A2CAE2F1AB4BB7500B6BC39 /* UIImage+MultiFormat.h in Headers */, + 325C46212233A02E004CAE11 /* UIColor+HexString.h in Headers */, 325312CA200F09910046BF1E /* SDWebImageTransition.h in Headers */, 4A2CAE1A1AB4BB6400B6BC39 /* SDWebImageOperation.h in Headers */, 32484765201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, @@ -692,6 +746,7 @@ 4A2CAE1B1AB4BB6800B6BC39 /* SDWebImageDownloader.h in Headers */, 3248476B201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 32D122322080B2EB003685A3 /* SDImageCachesManager.h in Headers */, + 325C4615223399F7004CAE11 /* SDImageGIFCoder+Private.h in Headers */, 32F7C0862030719600873181 /* UIImage+Transform.h in Headers */, 321E60C01F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 80B6DF7F2142B43300BCB334 /* NSImage+Compatibility.h in Headers */, @@ -713,12 +768,14 @@ 3257EAF921898AED0097B271 /* SDImageGraphics.h in Headers */, 32D3CDD021DDE87300C4DB49 /* UIImage+MemoryCacheCost.h in Headers */, 53761316155AD0D5005750A4 /* SDImageCache.h in Headers */, + 325C46262233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h in Headers */, 325312C8200F09910046BF1E /* SDWebImageTransition.h in Headers */, 32C0FDE12013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 321E60A21F38E8F600405457 /* SDImageGIFCoder.h in Headers */, 5D5B9142188EE8DD006D06BD /* NSData+ImageContentType.h in Headers */, 328BB6C12082581100760D6C /* SDDiskCache.h in Headers */, 53761318155AD0D5005750A4 /* SDWebImageCompat.h in Headers */, + 325C460222339330004CAE11 /* SDImageAssetManager.h in Headers */, 3290FA041FA478AF0047D20C /* SDImageFrame.h in Headers */, 80B6DF852142B44700BCB334 /* NSButton+WebCache.h in Headers */, 807A12281F89636300EC2A9B /* SDImageCodersManager.h in Headers */, @@ -736,12 +793,16 @@ 321E60BE1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 5376131E155AD0D5005750A4 /* SDWebImagePrefetcher.h in Headers */, 32F7C06F2030114C00873181 /* SDImageTransformer.h in Headers */, + 325C460E223394D8004CAE11 /* SDImageCachesManagerOperation.h in Headers */, + 325C461A22339B5F004CAE11 /* SDImageAPNGCoder+Private.h in Headers */, 321B378D2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, 32FDE8A220888789008D7530 /* SDWebImage.h in Headers */, 324DF4B4200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 5376131F155AD0D5005750A4 /* UIButton+WebCache.h in Headers */, + 325C460822339426004CAE11 /* SDWeakProxy.h in Headers */, 80B6DF802142B43A00BCB334 /* SDAnimatedImageRep.h in Headers */, 327054D4206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, + 325C46202233A02E004CAE11 /* UIColor+HexString.h in Headers */, 53761320155AD0D5005750A4 /* UIImageView+WebCache.h in Headers */, 328BB69C2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, 530E49E816464C25002868E7 /* SDWebImageOperation.h in Headers */, @@ -750,6 +811,7 @@ ABBE71A718C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h in Headers */, 320CAE152086F50500CFFC80 /* SDWebImageError.h in Headers */, 321B37812083290E00C0EA77 /* SDImageLoader.h in Headers */, + 325C4614223399F7004CAE11 /* SDImageGIFCoder+Private.h in Headers */, 321E60861F38E8C800405457 /* SDImageCoder.h in Headers */, 32484763201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80B6DF7E2142B43300BCB334 /* NSImage+Compatibility.h in Headers */, @@ -903,6 +965,7 @@ files = ( 3257EAFD21898AED0097B271 /* SDImageGraphics.m in Sources */, 3290FA0C1FA478AF0047D20C /* SDImageFrame.m in Sources */, + 325C46232233A02E004CAE11 /* UIColor+HexString.m in Sources */, 321E60C61F38E91700405457 /* UIImage+ForceDecode.m in Sources */, 328BB6A42081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 4A2CAE2E1AB4BB7500B6BC39 /* UIImage+GIF.m in Sources */, @@ -929,6 +992,7 @@ 32D1222C2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, 32B9B53F206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, 43A9186D1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, + 325C46292233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m in Sources */, 3248477D201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, 321E60AA1F38E8F600405457 /* SDImageGIFCoder.m in Sources */, 321E608E1F38E8C800405457 /* SDImageCoder.m in Sources */, @@ -937,11 +1001,13 @@ 4A2CAE2A1AB4BB7500B6BC39 /* NSData+ImageContentType.m in Sources */, 4A2CAE221AB4BB7000B6BC39 /* SDWebImageManager.m in Sources */, 4A2CAE191AB4BB6400B6BC39 /* SDWebImageCompat.m in Sources */, + 325C460B22339426004CAE11 /* SDWeakProxy.m in Sources */, 321B37892083290E00C0EA77 /* SDImageLoader.m in Sources */, 32484771201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 807A12301F89636300EC2A9B /* SDImageCodersManager.m in Sources */, 4A2CAE2C1AB4BB7500B6BC39 /* UIButton+WebCache.m in Sources */, 32D122262080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, + 325C460522339330004CAE11 /* SDImageAssetManager.m in Sources */, 324DF4BC200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 4A2CAE381AB4BB7500B6BC39 /* UIView+WebCacheOperation.m in Sources */, 32EB6D8E206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, @@ -950,6 +1016,7 @@ 4369C2801D9807EC007E863A /* UIView+WebCache.m in Sources */, 329A18611FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, 328BB6B22081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, + 325C4611223394D8004CAE11 /* SDImageCachesManagerOperation.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -959,6 +1026,7 @@ files = ( 3257EAFC21898AED0097B271 /* SDImageGraphics.m in Sources */, 3290FA0A1FA478AF0047D20C /* SDImageFrame.m in Sources */, + 325C46222233A02E004CAE11 /* UIColor+HexString.m in Sources */, 321E60C41F38E91700405457 /* UIImage+ForceDecode.m in Sources */, 328BB6A22081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 53761309155AD0D5005750A4 /* SDImageCache.m in Sources */, @@ -985,6 +1053,7 @@ 32D1222A2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, 32B9B53D206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, 43A9186B1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, + 325C46282233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m in Sources */, 3248477B201775F600AF9E5A /* SDAnimatedImageView+WebCache.m in Sources */, 321E60A81F38E8F600405457 /* SDImageGIFCoder.m in Sources */, 321E608C1F38E8C800405457 /* SDImageCoder.m in Sources */, @@ -993,11 +1062,13 @@ 530E49EC16464C84002868E7 /* SDWebImageDownloaderOperation.m in Sources */, 53406750167780C40042B59E /* SDWebImageCompat.m in Sources */, 321B37872083290E00C0EA77 /* SDImageLoader.m in Sources */, + 325C460A22339426004CAE11 /* SDWeakProxy.m in Sources */, 3248476F201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 807A122E1F89636300EC2A9B /* SDImageCodersManager.m in Sources */, A18A6CC9172DC28500419892 /* UIImage+GIF.m in Sources */, 32D122242080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, 324DF4BA200A14DC008A84CC /* SDWebImageDefine.m in Sources */, + 325C460422339330004CAE11 /* SDImageAssetManager.m in Sources */, AB615306192DA24600A2D8E9 /* UIView+WebCacheOperation.m in Sources */, 32EB6D91206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, 5D5B9145188EE8DD006D06BD /* NSData+ImageContentType.m in Sources */, @@ -1006,6 +1077,7 @@ 4369C27E1D9807EC007E863A /* UIView+WebCache.m in Sources */, 329A185F1FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, 328BB6B02081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, + 325C4610223394D8004CAE11 /* SDImageCachesManagerOperation.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SDWebImage/Private/NSBezierPath+RoundedCorners.h b/SDWebImage/Private/NSBezierPath+RoundedCorners.h new file mode 100644 index 00000000..224f2597 --- /dev/null +++ b/SDWebImage/Private/NSBezierPath+RoundedCorners.h @@ -0,0 +1,24 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +#if SD_MAC + +#import "UIImage+Transform.h" + +@interface NSBezierPath (RoundedCorners) + +/** + Convenience way to create a bezier path with the specify rounding corners on macOS. Same as the one on `UIBezierPath`. + */ ++ (nonnull instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius; + +@end + +#endif diff --git a/SDWebImage/Private/NSBezierPath+RoundedCorners.m b/SDWebImage/Private/NSBezierPath+RoundedCorners.m new file mode 100644 index 00000000..d217bf14 --- /dev/null +++ b/SDWebImage/Private/NSBezierPath+RoundedCorners.m @@ -0,0 +1,42 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "NSBezierPath+RoundedCorners.h" + +#if SD_MAC + +@implementation NSBezierPath (RoundedCorners) + ++ (instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius { + NSBezierPath *path = [NSBezierPath bezierPath]; + + CGFloat maxCorner = MIN(NSWidth(rect), NSHeight(rect)) / 2; + + CGFloat topLeftRadius = MIN(maxCorner, (corners & SDRectCornerTopLeft) ? cornerRadius : 0); + CGFloat topRightRadius = MIN(maxCorner, (corners & SDRectCornerTopRight) ? cornerRadius : 0); + CGFloat bottomLeftRadius = MIN(maxCorner, (corners & SDRectCornerBottomLeft) ? cornerRadius : 0); + CGFloat bottomRightRadius = MIN(maxCorner, (corners & SDRectCornerBottomRight) ? cornerRadius : 0); + + NSPoint topLeft = NSMakePoint(NSMinX(rect), NSMaxY(rect)); + NSPoint topRight = NSMakePoint(NSMaxX(rect), NSMaxY(rect)); + NSPoint bottomLeft = NSMakePoint(NSMinX(rect), NSMinY(rect)); + NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect)); + + [path moveToPoint:NSMakePoint(NSMidX(rect), NSMaxY(rect))]; + [path appendBezierPathWithArcFromPoint:topLeft toPoint:bottomLeft radius:topLeftRadius]; + [path appendBezierPathWithArcFromPoint:bottomLeft toPoint:bottomRight radius:bottomLeftRadius]; + [path appendBezierPathWithArcFromPoint:bottomRight toPoint:topRight radius:bottomRightRadius]; + [path appendBezierPathWithArcFromPoint:topRight toPoint:topLeft radius:topRightRadius]; + [path closePath]; + + return path; +} + +@end + +#endif diff --git a/SDWebImage/Private/SDImageAPNGCoder+Private.h b/SDWebImage/Private/SDImageAPNGCoder+Private.h new file mode 100644 index 00000000..93d53a6f --- /dev/null +++ b/SDWebImage/Private/SDImageAPNGCoder+Private.h @@ -0,0 +1,17 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import "SDImageAPNGCoder.h" + +@interface SDImageAPNGCoder () + +- (float)sd_frameDurationAtIndex:(NSUInteger)index source:(nonnull CGImageSourceRef)source; +- (NSUInteger)sd_imageLoopCountWithSource:(nonnull CGImageSourceRef)source; + +@end diff --git a/SDWebImage/Private/SDImageAssetManager.h b/SDWebImage/Private/SDImageAssetManager.h new file mode 100644 index 00000000..68184187 --- /dev/null +++ b/SDWebImage/Private/SDImageAssetManager.h @@ -0,0 +1,23 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" + +// Apple parse the Asset Catalog compiled file(`Assets.car`) by CoreUI.framework, however it's a private framework and there are no other ways to directly get the data. So we just process the normal bundle files :) + +@interface SDImageAssetManager : NSObject + +@property (nonatomic, strong, nonnull) NSMapTable *imageTable; + ++ (nonnull instancetype)sharedAssetManager; +- (nullable NSString *)getPathForName:(nonnull NSString *)name bundle:(nonnull NSBundle *)bundle preferredScale:(nonnull CGFloat *)scale; +- (nullable UIImage *)imageForName:(nonnull NSString *)name; +- (void)storeImage:(nonnull UIImage *)image forName:(nonnull NSString *)name; + +@end diff --git a/SDWebImage/Private/SDImageAssetManager.m b/SDWebImage/Private/SDImageAssetManager.m new file mode 100644 index 00000000..1dc5503c --- /dev/null +++ b/SDWebImage/Private/SDImageAssetManager.m @@ -0,0 +1,157 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDImageAssetManager.h" + +static NSArray *SDBundlePreferredScales() { + static NSArray *scales; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ +#if SD_WATCH + CGFloat screenScale = [WKInterfaceDevice currentDevice].screenScale; +#elif SD_UIKIT + CGFloat screenScale = [UIScreen mainScreen].scale; +#elif SD_MAC + CGFloat screenScale = [NSScreen mainScreen].backingScaleFactor; +#endif + if (screenScale <= 1) { + scales = @[@1,@2,@3]; + } else if (screenScale <= 2) { + scales = @[@2,@3,@1]; + } else { + scales = @[@3,@2,@1]; + } + }); + return scales; +} + +@implementation SDImageAssetManager { + dispatch_semaphore_t _lock; +} + ++ (instancetype)sharedAssetManager { + static dispatch_once_t onceToken; + static SDImageAssetManager *assetManager; + dispatch_once(&onceToken, ^{ + assetManager = [[SDImageAssetManager alloc] init]; + }); + return assetManager; +} + +- (instancetype)init { + self = [super init]; + if (self) { + NSPointerFunctionsOptions valueOptions; +#if SD_MAC + // Apple says that NSImage use a weak reference to value + valueOptions = NSPointerFunctionsWeakMemory; +#else + // Apple says that UIImage use a strong reference to value + valueOptions = NSPointerFunctionsStrongMemory; +#endif + _imageTable = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsCopyIn valueOptions:valueOptions]; + _lock = dispatch_semaphore_create(1); +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif + } + return self; +} + +- (void)dealloc { +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif +} + +- (void)didReceiveMemoryWarning:(NSNotification *)notification { + SD_LOCK(_lock); + [self.imageTable removeAllObjects]; + SD_UNLOCK(_lock); +} + +- (NSString *)getPathForName:(NSString *)name bundle:(NSBundle *)bundle preferredScale:(CGFloat *)scale { + NSParameterAssert(name); + NSParameterAssert(bundle); + NSString *path; + if (name.length == 0) { + return path; + } + if ([name hasSuffix:@"/"]) { + return path; + } + NSString *extension = name.pathExtension; + if (extension.length == 0) { + // If no extension, follow Apple's doc, check PNG format + extension = @"png"; + } + name = [name stringByDeletingPathExtension]; + + CGFloat providedScale = *scale; + NSArray *scales = SDBundlePreferredScales(); + + // Check if file name contains scale + for (size_t i = 0; i < scales.count; i++) { + NSNumber *scaleValue = scales[i]; + if ([name hasSuffix:[NSString stringWithFormat:@"@%@x", scaleValue]]) { + path = [bundle pathForResource:name ofType:extension]; + if (path) { + *scale = scaleValue.doubleValue; // override + return path; + } + } + } + + // Search with provided scale first + if (providedScale != 0) { + NSString *scaledName = [name stringByAppendingFormat:@"@%@x", @(providedScale)]; + path = [bundle pathForResource:scaledName ofType:extension]; + if (path) { + return path; + } + } + + // Search with preferred scale + for (size_t i = 0; i < scales.count; i++) { + NSNumber *scaleValue = scales[i]; + if (scaleValue.doubleValue == providedScale) { + // Ignore provided scale + continue; + } + NSString *scaledName = [name stringByAppendingFormat:@"@%@x", scaleValue]; + path = [bundle pathForResource:scaledName ofType:extension]; + if (path) { + *scale = scaleValue.doubleValue; // override + return path; + } + } + + // Search without scale + path = [bundle pathForResource:name ofType:extension]; + + return path; +} + +- (UIImage *)imageForName:(NSString *)name { + NSParameterAssert(name); + UIImage *image; + SD_LOCK(_lock); + image = [self.imageTable objectForKey:name]; + SD_UNLOCK(_lock); + return image; +} + +- (void)storeImage:(UIImage *)image forName:(NSString *)name { + NSParameterAssert(image); + NSParameterAssert(name); + SD_LOCK(_lock); + [self.imageTable setObject:image forKey:name]; + SD_UNLOCK(_lock); +} + +@end diff --git a/SDWebImage/Private/SDImageCachesManagerOperation.h b/SDWebImage/Private/SDImageCachesManagerOperation.h new file mode 100644 index 00000000..fddf78c1 --- /dev/null +++ b/SDWebImage/Private/SDImageCachesManagerOperation.h @@ -0,0 +1,21 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" + +// This is used for operation management, but not for operation queue execute +@interface SDImageCachesManagerOperation : NSOperation + +@property (nonatomic, assign, readonly) NSUInteger pendingCount; + +- (void)beginWithTotalCount:(NSUInteger)totalCount; +- (void)completeOne; +- (void)done; + +@end diff --git a/SDWebImage/Private/SDImageCachesManagerOperation.m b/SDWebImage/Private/SDImageCachesManagerOperation.m new file mode 100644 index 00000000..67f41450 --- /dev/null +++ b/SDWebImage/Private/SDImageCachesManagerOperation.m @@ -0,0 +1,60 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDImageCachesManagerOperation.h" + +@implementation SDImageCachesManagerOperation + +@synthesize executing = _executing; +@synthesize finished = _finished; +@synthesize cancelled = _cancelled; + +- (void)beginWithTotalCount:(NSUInteger)totalCount { + self.executing = YES; + self.finished = NO; + _pendingCount = totalCount; +} + +- (void)completeOne { + _pendingCount = _pendingCount > 0 ? _pendingCount - 1 : 0; +} + +- (void)cancel { + self.cancelled = YES; + [self reset]; +} + +- (void)done { + self.finished = YES; + self.executing = NO; + [self reset]; +} + +- (void)reset { + _pendingCount = 0; +} + +- (void)setFinished:(BOOL)finished { + [self willChangeValueForKey:@"isFinished"]; + _finished = finished; + [self didChangeValueForKey:@"isFinished"]; +} + +- (void)setExecuting:(BOOL)executing { + [self willChangeValueForKey:@"isExecuting"]; + _executing = executing; + [self didChangeValueForKey:@"isExecuting"]; +} + +- (void)setCancelled:(BOOL)cancelled { + [self willChangeValueForKey:@"isCancelled"]; + _cancelled = cancelled; + [self didChangeValueForKey:@"isCancelled"]; +} + +@end diff --git a/SDWebImage/Private/SDImageGIFCoder+Private.h b/SDWebImage/Private/SDImageGIFCoder+Private.h new file mode 100644 index 00000000..769d206c --- /dev/null +++ b/SDWebImage/Private/SDImageGIFCoder+Private.h @@ -0,0 +1,16 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import "SDImageGIFCoder.h" + +@interface SDImageGIFCoder () + +- (float)sd_frameDurationAtIndex:(NSUInteger)index source:(nonnull CGImageSourceRef)source; + +@end diff --git a/SDWebImage/Private/SDWeakProxy.h b/SDWebImage/Private/SDWeakProxy.h new file mode 100644 index 00000000..4fd16228 --- /dev/null +++ b/SDWebImage/Private/SDWeakProxy.h @@ -0,0 +1,19 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" + +@interface SDWeakProxy : NSProxy + +@property (nonatomic, weak, readonly, nullable) id target; + +- (nonnull instancetype)initWithTarget:(nonnull id)target; ++ (nonnull instancetype)proxyWithTarget:(nonnull id)target; + +@end diff --git a/SDWebImage/Private/SDWeakProxy.m b/SDWebImage/Private/SDWeakProxy.m new file mode 100644 index 00000000..19a45931 --- /dev/null +++ b/SDWebImage/Private/SDWeakProxy.m @@ -0,0 +1,79 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWeakProxy.h" + +@implementation SDWeakProxy + +- (instancetype)initWithTarget:(id)target { + _target = target; + return self; +} + ++ (instancetype)proxyWithTarget:(id)target { + return [[SDWeakProxy alloc] initWithTarget:target]; +} + +- (id)forwardingTargetForSelector:(SEL)selector { + return _target; +} + +- (void)forwardInvocation:(NSInvocation *)invocation { + void *null = NULL; + [invocation setReturnValue:&null]; +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { + return [NSObject instanceMethodSignatureForSelector:@selector(init)]; +} + +- (BOOL)respondsToSelector:(SEL)aSelector { + return [_target respondsToSelector:aSelector]; +} + +- (BOOL)isEqual:(id)object { + return [_target isEqual:object]; +} + +- (NSUInteger)hash { + return [_target hash]; +} + +- (Class)superclass { + return [_target superclass]; +} + +- (Class)class { + return [_target class]; +} + +- (BOOL)isKindOfClass:(Class)aClass { + return [_target isKindOfClass:aClass]; +} + +- (BOOL)isMemberOfClass:(Class)aClass { + return [_target isMemberOfClass:aClass]; +} + +- (BOOL)conformsToProtocol:(Protocol *)aProtocol { + return [_target conformsToProtocol:aProtocol]; +} + +- (BOOL)isProxy { + return YES; +} + +- (NSString *)description { + return [_target description]; +} + +- (NSString *)debugDescription { + return [_target debugDescription]; +} + +@end diff --git a/SDWebImage/Private/UIColor+HexString.h b/SDWebImage/Private/UIColor+HexString.h new file mode 100644 index 00000000..2a8a3d80 --- /dev/null +++ b/SDWebImage/Private/UIColor+HexString.h @@ -0,0 +1,18 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +@interface UIColor (HexString) + +/** + Convenience way to get hex string from color. The output should always be 32-bit RGBA hex string like `#00000000`. + */ +@property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString; + +@end diff --git a/SDWebImage/Private/UIColor+HexString.m b/SDWebImage/Private/UIColor+HexString.m new file mode 100644 index 00000000..aebb6e3b --- /dev/null +++ b/SDWebImage/Private/UIColor+HexString.m @@ -0,0 +1,42 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIColor+HexString.h" + +@implementation UIColor (HexString) + +- (NSString *)sd_hexString { + CGFloat red, green, blue, alpha; +#if SD_UIKIT + if (![self getRed:&red green:&green blue:&blue alpha:&alpha]) { + [self getWhite:&red alpha:&alpha]; + green = red; + blue = red; + } +#else + @try { + [self getRed:&red green:&green blue:&blue alpha:&alpha]; + } + @catch (NSException *exception) { + [self getWhite:&red alpha:&alpha]; + green = red; + blue = red; + } +#endif + + red = roundf(red * 255.f); + green = roundf(green * 255.f); + blue = roundf(blue * 255.f); + alpha = roundf(alpha * 255.f); + + uint hex = ((uint)alpha << 24) | ((uint)red << 16) | ((uint)green << 8) | ((uint)blue); + + return [NSString stringWithFormat:@"#%08x", hex]; +} + +@end diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index 6b779289..9fbd13e3 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -12,6 +12,7 @@ #import "SDImageCodersManager.h" #import "SDImageFrame.h" #import "UIImage+MemoryCacheCost.h" +#import "SDImageAssetManager.h" #import "objc/runtime.h" static CGFloat SDImageScaleFromPath(NSString *string) { @@ -29,169 +30,6 @@ static CGFloat SDImageScaleFromPath(NSString *string) { return scale; } -static NSArray *SDBundlePreferredScales() { - static NSArray *scales; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ -#if SD_WATCH - CGFloat screenScale = [WKInterfaceDevice currentDevice].screenScale; -#elif SD_UIKIT - CGFloat screenScale = [UIScreen mainScreen].scale; -#elif SD_MAC - CGFloat screenScale = [NSScreen mainScreen].backingScaleFactor; -#endif - if (screenScale <= 1) { - scales = @[@1,@2,@3]; - } else if (screenScale <= 2) { - scales = @[@2,@3,@1]; - } else { - scales = @[@3,@2,@1]; - } - }); - return scales; -} - -#pragma mark - UIImage cache for bundle - -// Apple parse the Asset Catalog compiled file(`Assets.car`) by CoreUI.framework, however it's a private framework and there are no other ways to directly get the data. So we just process the normal bundle files :) - -@interface SDImageAssetManager : NSObject { - dispatch_semaphore_t _lock; -} - -@property (nonatomic, strong) NSMapTable *imageTable; - -+ (instancetype)sharedAssetManager; -- (nullable NSString *)getPathForName:(nonnull NSString *)name bundle:(nonnull NSBundle *)bundle preferredScale:(CGFloat *)scale; -- (nullable UIImage *)imageForName:(nonnull NSString *)name; -- (void)storeImage:(nonnull UIImage *)image forName:(nonnull NSString *)name; - -@end - -@implementation SDImageAssetManager - -+ (instancetype)sharedAssetManager { - static dispatch_once_t onceToken; - static SDImageAssetManager *assetManager; - dispatch_once(&onceToken, ^{ - assetManager = [[SDImageAssetManager alloc] init]; - }); - return assetManager; -} - -- (instancetype)init { - self = [super init]; - if (self) { - NSPointerFunctionsOptions valueOptions; -#if SD_MAC - // Apple says that NSImage use a weak reference to value - valueOptions = NSPointerFunctionsWeakMemory; -#else - // Apple says that UIImage use a strong reference to value - valueOptions = NSPointerFunctionsStrongMemory; -#endif - _imageTable = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsCopyIn valueOptions:valueOptions]; - _lock = dispatch_semaphore_create(1); -#if SD_UIKIT - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; -#endif - } - return self; -} - -- (void)dealloc { -#if SD_UIKIT - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; -#endif -} - -- (void)didReceiveMemoryWarning:(NSNotification *)notification { - SD_LOCK(_lock); - [self.imageTable removeAllObjects]; - SD_UNLOCK(_lock); -} - -- (NSString *)getPathForName:(NSString *)name bundle:(NSBundle *)bundle preferredScale:(CGFloat *)scale { - NSParameterAssert(name); - NSParameterAssert(bundle); - NSString *path; - if (name.length == 0) { - return path; - } - if ([name hasSuffix:@"/"]) { - return path; - } - NSString *extension = name.pathExtension; - if (extension.length == 0) { - // If no extension, follow Apple's doc, check PNG format - extension = @"png"; - } - name = [name stringByDeletingPathExtension]; - - CGFloat providedScale = *scale; - NSArray *scales = SDBundlePreferredScales(); - - // Check if file name contains scale - for (size_t i = 0; i < scales.count; i++) { - NSNumber *scaleValue = scales[i]; - if ([name hasSuffix:[NSString stringWithFormat:@"@%@x", scaleValue]]) { - path = [bundle pathForResource:name ofType:extension]; - if (path) { - *scale = scaleValue.doubleValue; // override - return path; - } - } - } - - // Search with provided scale first - if (providedScale != 0) { - NSString *scaledName = [name stringByAppendingFormat:@"@%@x", @(providedScale)]; - path = [bundle pathForResource:scaledName ofType:extension]; - if (path) { - return path; - } - } - - // Search with preferred scale - for (size_t i = 0; i < scales.count; i++) { - NSNumber *scaleValue = scales[i]; - if (scaleValue.doubleValue == providedScale) { - // Ignore provided scale - continue; - } - NSString *scaledName = [name stringByAppendingFormat:@"@%@x", scaleValue]; - path = [bundle pathForResource:scaledName ofType:extension]; - if (path) { - *scale = scaleValue.doubleValue; // override - return path; - } - } - - // Search without scale - path = [bundle pathForResource:name ofType:extension]; - - return path; -} - -- (UIImage *)imageForName:(NSString *)name { - NSParameterAssert(name); - UIImage *image; - SD_LOCK(_lock); - image = [self.imageTable objectForKey:name]; - SD_UNLOCK(_lock); - return image; -} - -- (void)storeImage:(UIImage *)image forName:(NSString *)name { - NSParameterAssert(image); - NSParameterAssert(name); - SD_LOCK(_lock); - [self.imageTable setObject:image forKey:name]; - SD_UNLOCK(_lock); -} - -@end - @interface SDAnimatedImage () @property (nonatomic, strong) id coder; diff --git a/SDWebImage/SDAnimatedImageRep.m b/SDWebImage/SDAnimatedImageRep.m index 106dfc1d..06943d7d 100644 --- a/SDWebImage/SDAnimatedImageRep.m +++ b/SDWebImage/SDAnimatedImageRep.m @@ -10,21 +10,8 @@ #if SD_MAC -#import "SDImageGIFCoder.h" -#import "SDImageAPNGCoder.h" - -@interface SDImageGIFCoder () - -- (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source; - -@end - -@interface SDImageAPNGCoder () - -- (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source; -- (NSUInteger)sd_imageLoopCountWithSource:(CGImageSourceRef)source; - -@end +#import "SDImageGIFCoder+Private.h" +#import "SDImageAPNGCoder+Private.h" @interface SDAnimatedImageRep () diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index 7810744f..42c731d2 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -12,6 +12,7 @@ #import "UIImage+Metadata.h" #import "NSImage+Compatibility.h" +#import "SDWeakProxy.h" #import #import @@ -38,85 +39,6 @@ static NSUInteger SDDeviceFreeMemory() { return vm_stat.free_count * page_size; } -@interface SDWeakProxy : NSProxy - -@property (nonatomic, weak, readonly) id target; - -- (instancetype)initWithTarget:(id)target; -+ (instancetype)proxyWithTarget:(id)target; - -@end - -@implementation SDWeakProxy - -- (instancetype)initWithTarget:(id)target { - _target = target; - return self; -} - -+ (instancetype)proxyWithTarget:(id)target { - return [[SDWeakProxy alloc] initWithTarget:target]; -} - -- (id)forwardingTargetForSelector:(SEL)selector { - return _target; -} - -- (void)forwardInvocation:(NSInvocation *)invocation { - void *null = NULL; - [invocation setReturnValue:&null]; -} - -- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { - return [NSObject instanceMethodSignatureForSelector:@selector(init)]; -} - -- (BOOL)respondsToSelector:(SEL)aSelector { - return [_target respondsToSelector:aSelector]; -} - -- (BOOL)isEqual:(id)object { - return [_target isEqual:object]; -} - -- (NSUInteger)hash { - return [_target hash]; -} - -- (Class)superclass { - return [_target superclass]; -} - -- (Class)class { - return [_target class]; -} - -- (BOOL)isKindOfClass:(Class)aClass { - return [_target isKindOfClass:aClass]; -} - -- (BOOL)isMemberOfClass:(Class)aClass { - return [_target isMemberOfClass:aClass]; -} - -- (BOOL)conformsToProtocol:(Protocol *)aProtocol { - return [_target conformsToProtocol:aProtocol]; -} - -- (BOOL)isProxy { - return YES; -} - -- (NSString *)description { - return [_target description]; -} - -- (NSString *)debugDescription { - return [_target debugDescription]; -} - -@end - @interface SDAnimatedImageView () @property (nonatomic, strong, readwrite) UIImage *currentFrame; diff --git a/SDWebImage/SDImageCachesManager.m b/SDWebImage/SDImageCachesManager.m index 1da509f0..1700737e 100644 --- a/SDWebImage/SDImageCachesManager.m +++ b/SDWebImage/SDImageCachesManager.m @@ -7,68 +7,7 @@ */ #import "SDImageCachesManager.h" - -// This is used for operation management, but not for operation queue execute -@interface SDImageCachesManagerOperation : NSOperation - -@property (nonatomic, assign, readonly) NSUInteger pendingCount; - -- (void)beginWithTotalCount:(NSUInteger)totalCount; -- (void)completeOne; -- (void)done; - -@end - -@implementation SDImageCachesManagerOperation - -@synthesize executing = _executing; -@synthesize finished = _finished; -@synthesize cancelled = _cancelled; - -- (void)beginWithTotalCount:(NSUInteger)totalCount { - self.executing = YES; - self.finished = NO; - _pendingCount = totalCount; -} - -- (void)completeOne { - _pendingCount = _pendingCount > 0 ? _pendingCount - 1 : 0; -} - -- (void)cancel { - self.cancelled = YES; - [self reset]; -} - -- (void)done { - self.finished = YES; - self.executing = NO; - [self reset]; -} - -- (void)reset { - _pendingCount = 0; -} - -- (void)setFinished:(BOOL)finished { - [self willChangeValueForKey:@"isFinished"]; - _finished = finished; - [self didChangeValueForKey:@"isFinished"]; -} - -- (void)setExecuting:(BOOL)executing { - [self willChangeValueForKey:@"isExecuting"]; - _executing = executing; - [self didChangeValueForKey:@"isExecuting"]; -} - -- (void)setCancelled:(BOOL)cancelled { - [self willChangeValueForKey:@"isCancelled"]; - _cancelled = cancelled; - [self didChangeValueForKey:@"isCancelled"]; -} - -@end +#import "SDImageCachesManagerOperation.h" @implementation SDImageCachesManager diff --git a/SDWebImage/SDImageTransformer.m b/SDWebImage/SDImageTransformer.m index 0b0b58d7..9cbb0015 100644 --- a/SDWebImage/SDImageTransformer.m +++ b/SDWebImage/SDImageTransformer.m @@ -7,6 +7,7 @@ */ #import "SDImageTransformer.h" +#import "UIColor+HexString.h" #if SD_UIKIT || SD_MAC #import #endif @@ -21,48 +22,6 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * return [[key stringByAppendingString:SDImageTransformerKeySeparator] stringByAppendingString:transformerKey]; } -@interface UIColor (HexString) - -/** - Convenience way to get hex string from color. The output should always be 32-bit RGBA hex string like `#00000000`. - */ -@property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString; - -@end - -@implementation UIColor (HexString) - -- (NSString *)sd_hexString { - CGFloat red, green, blue, alpha; -#if SD_UIKIT - if (![self getRed:&red green:&green blue:&blue alpha:&alpha]) { - [self getWhite:&red alpha:&alpha]; - green = red; - blue = red; - } -#else - @try { - [self getRed:&red green:&green blue:&blue alpha:&alpha]; - } - @catch (NSException *exception) { - [self getWhite:&red alpha:&alpha]; - green = red; - blue = red; - } -#endif - - red = roundf(red * 255.f); - green = roundf(green * 255.f); - blue = roundf(blue * 255.f); - alpha = roundf(alpha * 255.f); - - uint hex = ((uint)alpha << 24) | ((uint)red << 16) | ((uint)green << 8) | ((uint)blue); - - return [NSString stringWithFormat:@"#%08x", hex]; -} - -@end - @interface SDImagePipelineTransformer () @property (nonatomic, copy, readwrite, nonnull) NSArray> *transformers; diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 6d844ec9..acf86fb1 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -9,6 +9,7 @@ #import "UIImage+Transform.h" #import "NSImage+Compatibility.h" #import "SDImageGraphics.h" +#import "NSBezierPath+RoundedCorners.h" #import #if SD_UIKIT || SD_MAC #import @@ -162,46 +163,6 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma return [UIColor colorWithRed:r green:g blue:b alpha:a]; } -#if SD_MAC -@interface NSBezierPath (RoundedCorners) - -/** - Convenience way to create a bezier path with the specify rounding corners on macOS. Same as the one on `UIBezierPath`. - */ -+ (nonnull instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius; - -@end - -@implementation NSBezierPath (RoundedCorners) - -+ (instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius { - NSBezierPath *path = [NSBezierPath bezierPath]; - - CGFloat maxCorner = MIN(NSWidth(rect), NSHeight(rect)) / 2; - - CGFloat topLeftRadius = MIN(maxCorner, (corners & SDRectCornerTopLeft) ? cornerRadius : 0); - CGFloat topRightRadius = MIN(maxCorner, (corners & SDRectCornerTopRight) ? cornerRadius : 0); - CGFloat bottomLeftRadius = MIN(maxCorner, (corners & SDRectCornerBottomLeft) ? cornerRadius : 0); - CGFloat bottomRightRadius = MIN(maxCorner, (corners & SDRectCornerBottomRight) ? cornerRadius : 0); - - NSPoint topLeft = NSMakePoint(NSMinX(rect), NSMaxY(rect)); - NSPoint topRight = NSMakePoint(NSMaxX(rect), NSMaxY(rect)); - NSPoint bottomLeft = NSMakePoint(NSMinX(rect), NSMinY(rect)); - NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect)); - - [path moveToPoint:NSMakePoint(NSMidX(rect), NSMaxY(rect))]; - [path appendBezierPathWithArcFromPoint:topLeft toPoint:bottomLeft radius:topLeftRadius]; - [path appendBezierPathWithArcFromPoint:bottomLeft toPoint:bottomRight radius:bottomLeftRadius]; - [path appendBezierPathWithArcFromPoint:bottomRight toPoint:topRight radius:bottomRightRadius]; - [path appendBezierPathWithArcFromPoint:topRight toPoint:topLeft radius:topRightRadius]; - [path closePath]; - - return path; -} - -@end -#endif - @implementation UIImage (Transform) - (void)sd_drawInRect:(CGRect)rect withScaleMode:(SDImageScaleMode)scaleMode clipsToBounds:(BOOL)clips { diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index fb70541b..30a05d56 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -408,7 +408,7 @@ files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-Tests Mac/Pods-Tests Mac-frameworks.sh", + "${PODS_ROOT}/Target Support Files/Pods-Tests Mac/Pods-Tests Mac-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Expecta-macOS/Expecta.framework", "${BUILT_PRODUCTS_DIR}/KVOController-macOS/KVOController.framework", "${BUILT_PRODUCTS_DIR}/SDWebImage-macOS/SDWebImage.framework", @@ -421,7 +421,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests Mac/Pods-Tests Mac-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tests Mac/Pods-Tests Mac-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; A07943B19E185DC24535F340 /* [CP] Embed Pods Frameworks */ = { @@ -430,7 +430,7 @@ files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-frameworks.sh", + "${PODS_ROOT}/Target Support Files/Pods-Tests/Pods-Tests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Expecta-iOS/Expecta.framework", "${BUILT_PRODUCTS_DIR}/KVOController-iOS/KVOController.framework", "${BUILT_PRODUCTS_DIR}/SDWebImage-iOS/SDWebImage.framework", @@ -443,7 +443,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tests/Pods-Tests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ From 9fb9ac7ad4b74a2ca286b956d0b5b2d64cea0cbb Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 9 Mar 2019 17:07:47 +0800 Subject: [PATCH 312/361] Fix the current transformer cache key generating rules, try to keep the image file extension as much as we can --- SDWebImage/SDImageTransformer.m | 18 +++++++++++++- Tests/Tests/SDImageTransformerTests.m | 36 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/SDWebImage/SDImageTransformer.m b/SDWebImage/SDImageTransformer.m index 0b0b58d7..bca1b68f 100644 --- a/SDWebImage/SDImageTransformer.m +++ b/SDWebImage/SDImageTransformer.m @@ -18,7 +18,23 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * if (!key || !transformerKey) { return nil; } - return [[key stringByAppendingString:SDImageTransformerKeySeparator] stringByAppendingString:transformerKey]; + // Find the file extension + NSURL *keyURL = [NSURL URLWithString:key]; + NSString *ext = keyURL ? keyURL.pathExtension : key.pathExtension; + if (ext.length > 0) { + // For non-file URL + if (keyURL && !keyURL.isFileURL) { + // keep anything except path (like URL query) + NSURLComponents *component = [NSURLComponents componentsWithURL:keyURL resolvingAgainstBaseURL:NO]; + component.path = [[[component.path.stringByDeletingPathExtension stringByAppendingString:SDImageTransformerKeySeparator] stringByAppendingString:transformerKey] stringByAppendingPathExtension:ext]; + return component.URL.absoluteString; + } else { + // file URL + return [[[key.stringByDeletingPathExtension stringByAppendingString:SDImageTransformerKeySeparator] stringByAppendingString:transformerKey] stringByAppendingPathExtension:ext]; + } + } else { + return [[key stringByAppendingString:SDImageTransformerKeySeparator] stringByAppendingString:transformerKey]; + } } @interface UIColor (HexString) diff --git a/Tests/Tests/SDImageTransformerTests.m b/Tests/Tests/SDImageTransformerTests.m index bcbfd7b8..57a19589 100644 --- a/Tests/Tests/SDImageTransformerTests.m +++ b/Tests/Tests/SDImageTransformerTests.m @@ -148,6 +148,42 @@ expect(CGSizeEqualToSize(transformedImage.size, size)).beTruthy(); } +- (void)test10TransformerKeyForCacheKey { + NSString *transformerKey = @"SDImageFlippingTransformer(1,0)"; + + // File path representation test cases + NSString *key = @"image.png"; + expect(SDTransformedKeyForKey(key, transformerKey)).equal(@"image-SDImageFlippingTransformer(1,0).png"); + + key = @"image"; + expect(SDTransformedKeyForKey(key, transformerKey)).equal(@"image-SDImageFlippingTransformer(1,0)"); + + key = @".image"; + expect(SDTransformedKeyForKey(key, transformerKey)).equal(@".image-SDImageFlippingTransformer(1,0)"); + + key = @"image."; + expect(SDTransformedKeyForKey(key, transformerKey)).equal(@"image.-SDImageFlippingTransformer(1,0)"); + + key = @"Test/image.png"; + expect(SDTransformedKeyForKey(key, transformerKey)).equal(@"Test/image-SDImageFlippingTransformer(1,0).png"); + + // URL representation test cases + key = @"http://foo/image.png"; + expect(SDTransformedKeyForKey(key, transformerKey)).equal(@"http://foo/image-SDImageFlippingTransformer(1,0).png"); + + key = @"http://foo/image"; + expect(SDTransformedKeyForKey(key, transformerKey)).equal(@"http://foo/image-SDImageFlippingTransformer(1,0)"); + + key = @"http://foo/.image"; + expect(SDTransformedKeyForKey(key, transformerKey)).equal(@"http://foo/.image-SDImageFlippingTransformer(1,0)"); + + key = @"http://foo/image.png?foo=bar#mark"; + expect(SDTransformedKeyForKey(key, transformerKey)).equal(@"http://foo/image-SDImageFlippingTransformer(1,0).png?foo=bar#mark"); + + key = @"ftp://root:password@foo.com/image.png"; + expect(SDTransformedKeyForKey(key, transformerKey)).equal(@"ftp://root:password@foo.com/image-SDImageFlippingTransformer(1,0).png"); +} + #pragma mark - Helper - (UIImage *)testImage { From 146530e1a2504772fa3f2f1cdf3291759a07786f Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 10 Mar 2019 10:53:46 +0800 Subject: [PATCH 313/361] Change the naming of private headers of internal methods, from `+Private.h` naming into `Internal.h` naming, follow other popular framework's naming rules --- SDWebImage.xcodeproj/project.pbxproj | 24 +++++++++---------- ...r+Private.h => SDImageAPNGCoderInternal.h} | 0 ...er+Private.h => SDImageGIFCoderInternal.h} | 0 SDWebImage/SDAnimatedImageRep.m | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) rename SDWebImage/Private/{SDImageAPNGCoder+Private.h => SDImageAPNGCoderInternal.h} (100%) rename SDWebImage/Private/{SDImageGIFCoder+Private.h => SDImageGIFCoderInternal.h} (100%) diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 4609fadf..2fb6d60b 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -75,10 +75,10 @@ 325C460F223394D8004CAE11 /* SDImageCachesManagerOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C460C223394D8004CAE11 /* SDImageCachesManagerOperation.h */; settings = {ATTRIBUTES = (Private, ); }; }; 325C4610223394D8004CAE11 /* SDImageCachesManagerOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C460D223394D8004CAE11 /* SDImageCachesManagerOperation.m */; }; 325C4611223394D8004CAE11 /* SDImageCachesManagerOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C460D223394D8004CAE11 /* SDImageCachesManagerOperation.m */; }; - 325C4614223399F7004CAE11 /* SDImageGIFCoder+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C4612223399F7004CAE11 /* SDImageGIFCoder+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 325C4615223399F7004CAE11 /* SDImageGIFCoder+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C4612223399F7004CAE11 /* SDImageGIFCoder+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 325C461A22339B5F004CAE11 /* SDImageAPNGCoder+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C461822339B5F004CAE11 /* SDImageAPNGCoder+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 325C461B22339B5F004CAE11 /* SDImageAPNGCoder+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C461822339B5F004CAE11 /* SDImageAPNGCoder+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C4614223399F7004CAE11 /* SDImageGIFCoderInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C4612223399F7004CAE11 /* SDImageGIFCoderInternal.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C4615223399F7004CAE11 /* SDImageGIFCoderInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C4612223399F7004CAE11 /* SDImageGIFCoderInternal.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C461A22339B5F004CAE11 /* SDImageAPNGCoderInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C461822339B5F004CAE11 /* SDImageAPNGCoderInternal.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 325C461B22339B5F004CAE11 /* SDImageAPNGCoderInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C461822339B5F004CAE11 /* SDImageAPNGCoderInternal.h */; settings = {ATTRIBUTES = (Private, ); }; }; 325C46202233A02E004CAE11 /* UIColor+HexString.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C461E2233A02E004CAE11 /* UIColor+HexString.h */; settings = {ATTRIBUTES = (Private, ); }; }; 325C46212233A02E004CAE11 /* UIColor+HexString.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C461E2233A02E004CAE11 /* UIColor+HexString.h */; settings = {ATTRIBUTES = (Private, ); }; }; 325C46222233A02E004CAE11 /* UIColor+HexString.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C461F2233A02E004CAE11 /* UIColor+HexString.m */; }; @@ -289,8 +289,8 @@ 325C460722339426004CAE11 /* SDWeakProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWeakProxy.m; sourceTree = ""; }; 325C460C223394D8004CAE11 /* SDImageCachesManagerOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageCachesManagerOperation.h; sourceTree = ""; }; 325C460D223394D8004CAE11 /* SDImageCachesManagerOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageCachesManagerOperation.m; sourceTree = ""; }; - 325C4612223399F7004CAE11 /* SDImageGIFCoder+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SDImageGIFCoder+Private.h"; sourceTree = ""; }; - 325C461822339B5F004CAE11 /* SDImageAPNGCoder+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SDImageAPNGCoder+Private.h"; sourceTree = ""; }; + 325C4612223399F7004CAE11 /* SDImageGIFCoderInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageGIFCoderInternal.h; sourceTree = ""; }; + 325C461822339B5F004CAE11 /* SDImageAPNGCoderInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageAPNGCoderInternal.h; sourceTree = ""; }; 325C461E2233A02E004CAE11 /* UIColor+HexString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIColor+HexString.h"; sourceTree = ""; }; 325C461F2233A02E004CAE11 /* UIColor+HexString.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIColor+HexString.m"; sourceTree = ""; }; 325C46242233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSBezierPath+RoundedCorners.h"; sourceTree = ""; }; @@ -491,8 +491,8 @@ 325C460122339330004CAE11 /* SDImageAssetManager.m */, 325C460C223394D8004CAE11 /* SDImageCachesManagerOperation.h */, 325C460D223394D8004CAE11 /* SDImageCachesManagerOperation.m */, - 325C4612223399F7004CAE11 /* SDImageGIFCoder+Private.h */, - 325C461822339B5F004CAE11 /* SDImageAPNGCoder+Private.h */, + 325C4612223399F7004CAE11 /* SDImageGIFCoderInternal.h */, + 325C461822339B5F004CAE11 /* SDImageAPNGCoderInternal.h */, 325C461E2233A02E004CAE11 /* UIColor+HexString.h */, 325C461F2233A02E004CAE11 /* UIColor+HexString.m */, 325C46242233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h */, @@ -729,7 +729,7 @@ 4A2CAE251AB4BB7000B6BC39 /* SDWebImagePrefetcher.h in Headers */, 328BB6CF2082581100760D6C /* SDMemoryCache.h in Headers */, 325C460F223394D8004CAE11 /* SDImageCachesManagerOperation.h in Headers */, - 325C461B22339B5F004CAE11 /* SDImageAPNGCoder+Private.h in Headers */, + 325C461B22339B5F004CAE11 /* SDImageAPNGCoderInternal.h in Headers */, 321E60881F38E8C800405457 /* SDImageCoder.h in Headers */, 4A2CAE371AB4BB7500B6BC39 /* UIView+WebCacheOperation.h in Headers */, 321B37832083290E00C0EA77 /* SDImageLoader.h in Headers */, @@ -746,7 +746,7 @@ 4A2CAE1B1AB4BB6800B6BC39 /* SDWebImageDownloader.h in Headers */, 3248476B201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 32D122322080B2EB003685A3 /* SDImageCachesManager.h in Headers */, - 325C4615223399F7004CAE11 /* SDImageGIFCoder+Private.h in Headers */, + 325C4615223399F7004CAE11 /* SDImageGIFCoderInternal.h in Headers */, 32F7C0862030719600873181 /* UIImage+Transform.h in Headers */, 321E60C01F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 80B6DF7F2142B43300BCB334 /* NSImage+Compatibility.h in Headers */, @@ -794,7 +794,7 @@ 5376131E155AD0D5005750A4 /* SDWebImagePrefetcher.h in Headers */, 32F7C06F2030114C00873181 /* SDImageTransformer.h in Headers */, 325C460E223394D8004CAE11 /* SDImageCachesManagerOperation.h in Headers */, - 325C461A22339B5F004CAE11 /* SDImageAPNGCoder+Private.h in Headers */, + 325C461A22339B5F004CAE11 /* SDImageAPNGCoderInternal.h in Headers */, 321B378D2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, 32FDE8A220888789008D7530 /* SDWebImage.h in Headers */, 324DF4B4200A14DC008A84CC /* SDWebImageDefine.h in Headers */, @@ -811,7 +811,7 @@ ABBE71A718C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h in Headers */, 320CAE152086F50500CFFC80 /* SDWebImageError.h in Headers */, 321B37812083290E00C0EA77 /* SDImageLoader.h in Headers */, - 325C4614223399F7004CAE11 /* SDImageGIFCoder+Private.h in Headers */, + 325C4614223399F7004CAE11 /* SDImageGIFCoderInternal.h in Headers */, 321E60861F38E8C800405457 /* SDImageCoder.h in Headers */, 32484763201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80B6DF7E2142B43300BCB334 /* NSImage+Compatibility.h in Headers */, diff --git a/SDWebImage/Private/SDImageAPNGCoder+Private.h b/SDWebImage/Private/SDImageAPNGCoderInternal.h similarity index 100% rename from SDWebImage/Private/SDImageAPNGCoder+Private.h rename to SDWebImage/Private/SDImageAPNGCoderInternal.h diff --git a/SDWebImage/Private/SDImageGIFCoder+Private.h b/SDWebImage/Private/SDImageGIFCoderInternal.h similarity index 100% rename from SDWebImage/Private/SDImageGIFCoder+Private.h rename to SDWebImage/Private/SDImageGIFCoderInternal.h diff --git a/SDWebImage/SDAnimatedImageRep.m b/SDWebImage/SDAnimatedImageRep.m index 06943d7d..1e473b2b 100644 --- a/SDWebImage/SDAnimatedImageRep.m +++ b/SDWebImage/SDAnimatedImageRep.m @@ -10,8 +10,8 @@ #if SD_MAC -#import "SDImageGIFCoder+Private.h" -#import "SDImageAPNGCoder+Private.h" +#import "SDImageGIFCoderInternal.h" +#import "SDImageAPNGCoderInternal.h" @interface SDAnimatedImageRep () From ce753df0cc0c3c039ffb36b369136b6d49d8913d Mon Sep 17 00:00:00 2001 From: Insofan <282132315@qq.com> Date: Thu, 14 Mar 2019 15:27:29 +0800 Subject: [PATCH 314/361] simplify assign downloaderOperation's minimumProgressInterval code --- SDWebImage/SDWebImageDownloader.m | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 60c6767e..240e6372 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -291,9 +291,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; } if ([operation respondsToSelector:@selector(setMinimumProgressInterval:)]) { - NSTimeInterval minimumProgressInterval = self.config.minimumProgressInterval; - minimumProgressInterval = MIN(MAX(minimumProgressInterval, 0), 1); - operation.minimumProgressInterval = minimumProgressInterval; + operation.minimumProgressInterval = MIN(MAX(self.config.minimumProgressInterval, 0), 1); } if (options & SDWebImageDownloaderHighPriority) { From 528871455dbb698b18efe3f184530b6dfbef074c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 14 Mar 2019 21:51:59 +0800 Subject: [PATCH 315/361] Update travis script to avoid using pre-release of cocoapods --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9fc5c56e..372893da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ notifications: before_install: - env - locale - - gem install cocoapods --pre --no-rdoc --no-ri --no-document --quiet + - gem install cocoapods --no-rdoc --no-ri --no-document --quiet - gem install xcpretty --no-rdoc --no-ri --no-document --quiet - pod --version - pod setup --silent > /dev/null From 4483cdcc23c855eaf93ee0beced0ec01117620b2 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 15 Mar 2019 15:46:17 +0800 Subject: [PATCH 316/361] update CHANGELOG --- CHANGELOG.md | 10 ++++++++++ Docs/API-Diff/5.0/apidiff.html | 1 + 2 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 121a478a..fd88a92c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## [5.0.0-beta6 - 5.0 Beta, on Mar 15th, 2019](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta6) +See [all tickets marked for the 5.0.0-beta6 release](https://github.com/rs/SDWebImage/milestone/30) + +#### Fixes +- Fix the issue that SDWebImagePrefetch in 5.x, will submit all prefetch URLs to manager without any concurrent limit #2631 +- Fix the current transformer cache key generating rules, try to keep the image file extension #2635 + +#### Project +- Move some internal classes into private header files, make it easy to maintain the code #2634 + ## [4.4.6 - 4.4 patch, on Feb 26th, 2019](https://github.com/SDWebImage/SDWebImage/releases/tag/4.4.6) See [all tickets marked for the 4.4.6 release](https://github.com/SDWebImage/SDWebImage/milestone/33) diff --git a/Docs/API-Diff/5.0/apidiff.html b/Docs/API-Diff/5.0/apidiff.html index ce82699a..0dbd1fd0 100644 --- a/Docs/API-Diff/5.0/apidiff.html +++ b/Docs/API-Diff/5.0/apidiff.html @@ -1104,6 +1104,7 @@
Added SDWebImagePrefetchToken
Added -[SDWebImagePrefetchToken cancel]
Added SDWebImagePrefetchToken.urls
+
Added SDWebImagePrefetcher.maxConcurrentPrefetchCount
Added SDWebImagePrefetcher.context
Added SDWebImagePrefetcher.delegateQueue
From 21b2244b8161f3763af39b7c4aa5529460084fd7 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 15 Mar 2019 15:47:29 +0800 Subject: [PATCH 317/361] Bumped version to 5.0.0-beta6 --- SDWebImage.podspec | 2 +- WebImage/Info.plist | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SDWebImage.podspec b/SDWebImage.podspec index 4ed29a05..8f282506 100644 --- a/SDWebImage.podspec +++ b/SDWebImage.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'SDWebImage' - s.version = '5.0.0-beta5' + s.version = '5.0.0-beta6' s.osx.deployment_target = '10.10' s.ios.deployment_target = '8.0' diff --git a/WebImage/Info.plist b/WebImage/Info.plist index da8b600c..ef4c0965 100644 --- a/WebImage/Info.plist +++ b/WebImage/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.0.0-beta5 + 5.0.0-beta6 CFBundleSignature ???? CFBundleVersion - 5.0.0-beta5 + 5.0.0-beta6 NSPrincipalClass From 9c3b7a84b7f21f3e85f90cbe20260831a899e680 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 15 Mar 2019 23:51:18 +0800 Subject: [PATCH 318/361] Break strong retain cycle for prefetch block --- SDWebImage/SDWebImagePrefetcher.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index 73dda304..56ccac1c 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -107,7 +107,11 @@ for (NSURL *url in token.urls) { __weak typeof(self) wself = self; SDAsyncBlockOperation *prefetchOperation = [SDAsyncBlockOperation blockOperationWithBlock:^(SDAsyncBlockOperation * _Nonnull asyncOperation) { - id operation = [self.manager loadImageWithURL:url options:self.options context:self.context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + __strong typeof(wself) sself = wself; + if (!sself) { + return; + } + id operation = [sself.manager loadImageWithURL:url options:sself.options context:sself.context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { __strong typeof(wself) sself = wself; if (!sself) { return; From 06865847717893fd1bafc6da7b7a8189a625ec53 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Sat, 16 Mar 2019 00:16:01 +0800 Subject: [PATCH 319/361] Remove shadow variable warning --- SDWebImage/SDWebImagePrefetcher.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index 56ccac1c..82cb1054 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -107,11 +107,11 @@ for (NSURL *url in token.urls) { __weak typeof(self) wself = self; SDAsyncBlockOperation *prefetchOperation = [SDAsyncBlockOperation blockOperationWithBlock:^(SDAsyncBlockOperation * _Nonnull asyncOperation) { - __strong typeof(wself) sself = wself; - if (!sself) { + __strong typeof(wself) strongSelf = wself; + if (!strongSelf) { return; } - id operation = [sself.manager loadImageWithURL:url options:sself.options context:sself.context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + id operation = [strongSelf.manager loadImageWithURL:url options:strongSelf.options context:strongSelf.context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { __strong typeof(wself) sself = wself; if (!sself) { return; From ff3a3e827d2741721d1ac3307da91ce99113cba8 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Mon, 18 Mar 2019 12:01:46 +0800 Subject: [PATCH 320/361] Fix prefetch cancellation issues --- SDWebImage/Private/SDAsyncBlockOperation.m | 22 ++++++++++++++---- SDWebImage/SDWebImagePrefetcher.m | 27 ++++++++++++++++------ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/SDWebImage/Private/SDAsyncBlockOperation.m b/SDWebImage/Private/SDAsyncBlockOperation.m index 5e3e0fe5..8862ef8e 100644 --- a/SDWebImage/Private/SDAsyncBlockOperation.m +++ b/SDWebImage/Private/SDAsyncBlockOperation.m @@ -10,14 +10,17 @@ @interface SDAsyncBlockOperation () -@property (nonatomic, assign) BOOL isExecuting; -@property (nonatomic, assign) BOOL isFinished; +@property (assign, nonatomic, getter = isExecuting) BOOL executing; +@property (assign, nonatomic, getter = isFinished) BOOL finished; @property (nonatomic, copy, nonnull) SDAsyncBlock executionBlock; @end @implementation SDAsyncBlockOperation +@synthesize executing = _executing; +@synthesize finished = _finished; + - (nonnull instancetype)initWithBlock:(nonnull SDAsyncBlock)block { self = [super init]; if (self) { @@ -32,8 +35,12 @@ } - (void)start { + if (self.isCancelled) { + return; + } + [self willChangeValueForKey:@"isExecuting"]; - self.isExecuting = YES; + self.executing = YES; [self didChangeValueForKey:@"isExecuting"]; if (self.executionBlock) { @@ -43,11 +50,16 @@ } } +- (void)cancel { + [super cancel]; + [self complete]; +} + - (void)complete { [self willChangeValueForKey:@"isExecuting"]; [self willChangeValueForKey:@"isFinished"]; - self.isExecuting = NO; - self.isFinished = YES; + self.executing = NO; + self.finished = YES; [self didChangeValueForKey:@"isExecuting"]; [self didChangeValueForKey:@"isFinished"]; } diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index 82cb1054..ddf532e7 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -22,7 +22,8 @@ } @property (nonatomic, copy, readwrite) NSArray *urls; -@property (nonatomic, strong) NSPointerArray *operations; +@property (nonatomic, strong) NSPointerArray *loadOperations; +@property (nonatomic, strong) NSPointerArray *prefetchOperations; @property (nonatomic, weak) SDWebImagePrefetcher *prefetcher; @property (nonatomic, copy, nullable) SDWebImagePrefetcherCompletionBlock completionBlock; @property (nonatomic, copy, nullable) SDWebImagePrefetcherProgressBlock progressBlock; @@ -93,7 +94,8 @@ token->_finishedCount = 0; token->_totalCount = token.urls.count; atomic_flag_clear(&(token->_isAllFinished)); - token.operations = [NSPointerArray weakObjectsPointerArray]; + token.loadOperations = [NSPointerArray weakObjectsPointerArray]; + token.prefetchOperations = [NSPointerArray weakObjectsPointerArray]; token.progressBlock = progressBlock; token.completionBlock = completionBlock; [self addRunningToken:token]; @@ -103,12 +105,12 @@ } - (void)startPrefetchWithToken:(SDWebImagePrefetchToken * _Nonnull)token { - NSPointerArray *operations = token.operations; + NSPointerArray *operations = token.loadOperations; for (NSURL *url in token.urls) { __weak typeof(self) wself = self; SDAsyncBlockOperation *prefetchOperation = [SDAsyncBlockOperation blockOperationWithBlock:^(SDAsyncBlockOperation * _Nonnull asyncOperation) { __strong typeof(wself) strongSelf = wself; - if (!strongSelf) { + if (!strongSelf || asyncOperation.isCancelled) { return; } id operation = [strongSelf.manager loadImageWithURL:url options:strongSelf.options context:strongSelf.context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { @@ -119,7 +121,6 @@ if (!finished) { return; } - [asyncOperation complete]; atomic_fetch_add_explicit(&(token->_finishedCount), 1, memory_order_relaxed); if (error) { @@ -137,11 +138,15 @@ [sself removeRunningToken:token]; } } + [asyncOperation complete]; }]; @synchronized (token) { [operations addPointer:(__bridge void *)operation]; } }]; + @synchronized (token) { + [token.prefetchOperations addPointer:(__bridge void *)prefetchOperation]; + } [self.prefetchQueue addOperation:prefetchOperation]; } } @@ -256,12 +261,20 @@ - (void)cancel { @synchronized (self) { - for (id operation in self.operations) { + [self.prefetchOperations compact]; + for (id operation in self.prefetchOperations) { + SDAsyncBlockOperation *asyncBlockOperation = operation; + [asyncBlockOperation cancel]; + } + self.prefetchOperations.count = 0; + + [self.loadOperations compact]; + for (id operation in self.loadOperations) { if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) { [operation cancel]; } } - self.operations.count = 0; + self.loadOperations.count = 0; } self.completionBlock = nil; self.progressBlock = nil; From 97e6b64f0e1c35d5f2b855dc8d322a1e43a94964 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Tue, 19 Mar 2019 10:27:41 +0200 Subject: [PATCH 321/361] Updated logos per #2579 --- SDWebImage_logo.png | Bin 8210 -> 34483 bytes SDWebImage_logo_small.png | Bin 1981 -> 9955 bytes 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 SDWebImage_logo.png mode change 100644 => 100755 SDWebImage_logo_small.png diff --git a/SDWebImage_logo.png b/SDWebImage_logo.png old mode 100644 new mode 100755 index bd2ec3a5faedc91a024b5c3d824a2eb7722e6f09..ee2d81f34ce7299b384b26533426c6c3bb9d02d3 GIT binary patch literal 34483 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 D^*6~+J=V%S4>y(b9ovhx*G9CEc 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 From de4e2344babb3974cd448c75431053131c96236d Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Tue, 19 Mar 2019 10:29:46 +0200 Subject: [PATCH 322/361] Updated README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3f321277..b06c0ea8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- +

From ebf41a3b0107a768845d0352b1c5212503d07c03 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Tue, 19 Mar 2019 20:26:00 +0800 Subject: [PATCH 323/361] Consolidate cancel code --- SDWebImage/SDWebImagePrefetcher.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index ddf532e7..c40055ec 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -263,8 +263,9 @@ @synchronized (self) { [self.prefetchOperations compact]; for (id operation in self.prefetchOperations) { - SDAsyncBlockOperation *asyncBlockOperation = operation; - [asyncBlockOperation cancel]; + if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) { + [operation cancel]; + } } self.prefetchOperations.count = 0; From 21565dbc8faca02cb1ea94b77ed79e48802c3e2c Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 20 Mar 2019 11:21:04 +0800 Subject: [PATCH 324/361] Add assert to check operation nil --- SDWebImage/SDWebImagePrefetcher.m | 1 + 1 file changed, 1 insertion(+) diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index c40055ec..0540bab4 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -140,6 +140,7 @@ } [asyncOperation complete]; }]; + NSAssert(operation != nil, @"Operation should not be nil, [SDWebImageManager loadImageWithURL:options:context:progress:completed:] break prefetch logic"); @synchronized (token) { [operations addPointer:(__bridge void *)operation]; } From 367f4454b649a354372f2eb1a6e23605e417f52f Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 18 Mar 2019 18:46:42 +0800 Subject: [PATCH 325/361] Add the private @weakify @strongify @onExit macros to simplify the code in implementation files --- SDWebImage.xcodeproj/project.pbxproj | 18 + SDWebImage/Private/SDImageAssetManager.m | 1 + SDWebImage/Private/SDInternalMacros.h | 61 ++ SDWebImage/Private/SDInternalMacros.m | 13 + SDWebImage/Private/metamacros.h | 667 +++++++++++++++++++++ SDWebImage/SDAnimatedImageView.m | 1 + SDWebImage/SDImageCodersManager.m | 1 + SDWebImage/SDImageLoadersManager.m | 1 + SDWebImage/SDMemoryCache.m | 1 + SDWebImage/SDWebImageCompat.h | 8 - SDWebImage/SDWebImageDownloader.m | 1 + SDWebImage/SDWebImageDownloaderOperation.m | 1 + SDWebImage/SDWebImageManager.m | 1 + 13 files changed, 767 insertions(+), 8 deletions(-) create mode 100644 SDWebImage/Private/SDInternalMacros.h create mode 100644 SDWebImage/Private/SDInternalMacros.m create mode 100644 SDWebImage/Private/metamacros.h diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 2fb6d60b..45536ee5 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -115,6 +115,12 @@ 329A185B1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; 329A185F1FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; 329A18611FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; + 329F1236223FAA3B00B309FD /* metamacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 329F1235223FAA3B00B309FD /* metamacros.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 329F1237223FAA3B00B309FD /* metamacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 329F1235223FAA3B00B309FD /* metamacros.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 329F1240223FAD3400B309FD /* SDInternalMacros.m in Sources */ = {isa = PBXBuildFile; fileRef = 329F123E223FAD3400B309FD /* SDInternalMacros.m */; }; + 329F1241223FAD3400B309FD /* SDInternalMacros.m in Sources */ = {isa = PBXBuildFile; fileRef = 329F123E223FAD3400B309FD /* SDInternalMacros.m */; }; + 329F1242223FAD3400B309FD /* SDInternalMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 329F123F223FAD3400B309FD /* SDInternalMacros.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 329F1243223FAD3400B309FD /* SDInternalMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 329F123F223FAD3400B309FD /* SDInternalMacros.h */; settings = {ATTRIBUTES = (Private, ); }; }; 32B5CC60222F89C2005EB74E /* SDAsyncBlockOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B5CC5E222F89C2005EB74E /* SDAsyncBlockOperation.h */; settings = {ATTRIBUTES = (Private, ); }; }; 32B5CC61222F89C2005EB74E /* SDAsyncBlockOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B5CC5F222F89C2005EB74E /* SDAsyncBlockOperation.m */; }; 32B5CC62222F89F6005EB74E /* SDAsyncBlockOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B5CC5E222F89C2005EB74E /* SDAsyncBlockOperation.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -309,6 +315,9 @@ 3290FA031FA478AF0047D20C /* SDImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageFrame.m; sourceTree = ""; }; 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Metadata.h"; sourceTree = ""; }; 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Metadata.m"; sourceTree = ""; }; + 329F1235223FAA3B00B309FD /* metamacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metamacros.h; sourceTree = ""; }; + 329F123E223FAD3400B309FD /* SDInternalMacros.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDInternalMacros.m; sourceTree = ""; }; + 329F123F223FAD3400B309FD /* SDInternalMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDInternalMacros.h; sourceTree = ""; }; 32B5CC5E222F89C2005EB74E /* SDAsyncBlockOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDAsyncBlockOperation.h; sourceTree = ""; }; 32B5CC5F222F89C2005EB74E /* SDAsyncBlockOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDAsyncBlockOperation.m; sourceTree = ""; }; 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderConfig.h; sourceTree = ""; }; @@ -497,6 +506,9 @@ 325C461F2233A02E004CAE11 /* UIColor+HexString.m */, 325C46242233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h */, 325C46252233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m */, + 329F123F223FAD3400B309FD /* SDInternalMacros.h */, + 329F123E223FAD3400B309FD /* SDInternalMacros.m */, + 329F1235223FAA3B00B309FD /* metamacros.h */, ); path = Private; sourceTree = ""; @@ -715,6 +727,7 @@ 80B6DF842142B44600BCB334 /* NSButton+WebCache.h in Headers */, 43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 3290FA061FA478AF0047D20C /* SDImageFrame.h in Headers */, + 329F1237223FAA3B00B309FD /* metamacros.h in Headers */, 324DF4B6200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 807A122A1F89636300EC2A9B /* SDImageCodersManager.h in Headers */, 4A2CAE211AB4BB7000B6BC39 /* SDWebImageManager.h in Headers */, @@ -749,6 +762,7 @@ 325C4615223399F7004CAE11 /* SDImageGIFCoderInternal.h in Headers */, 32F7C0862030719600873181 /* UIImage+Transform.h in Headers */, 321E60C01F38E91700405457 /* UIImage+ForceDecode.h in Headers */, + 329F1243223FAD3400B309FD /* SDInternalMacros.h in Headers */, 80B6DF7F2142B43300BCB334 /* NSImage+Compatibility.h in Headers */, 32C0FDE32013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 32F7C0712030114C00873181 /* SDImageTransformer.h in Headers */, @@ -780,6 +794,7 @@ 80B6DF852142B44700BCB334 /* NSButton+WebCache.h in Headers */, 807A12281F89636300EC2A9B /* SDImageCodersManager.h in Headers */, 32B9B537206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, + 329F1236223FAA3B00B309FD /* metamacros.h in Headers */, 32484775201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 321E60941F38E8ED00405457 /* SDImageIOCoder.h in Headers */, 329A18591FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, @@ -814,6 +829,7 @@ 325C4614223399F7004CAE11 /* SDImageGIFCoderInternal.h in Headers */, 321E60861F38E8C800405457 /* SDImageCoder.h in Headers */, 32484763201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, + 329F1242223FAD3400B309FD /* SDInternalMacros.h in Headers */, 80B6DF7E2142B43300BCB334 /* NSImage+Compatibility.h in Headers */, 32D1221E2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, AB615303192DA24600A2D8E9 /* UIView+WebCacheOperation.h in Headers */, @@ -971,6 +987,7 @@ 4A2CAE2E1AB4BB7500B6BC39 /* UIImage+GIF.m in Sources */, 80B6DF822142B44400BCB334 /* NSButton+WebCache.m in Sources */, 32D3CDCF21DDE87300C4DB49 /* UIImage+MemoryCacheCost.m in Sources */, + 329F1241223FAD3400B309FD /* SDInternalMacros.m in Sources */, 320CAE1D2086F50500CFFC80 /* SDWebImageError.m in Sources */, 32CF1C0F1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, 328BB6D52082581100760D6C /* SDMemoryCache.m in Sources */, @@ -1032,6 +1049,7 @@ 53761309155AD0D5005750A4 /* SDImageCache.m in Sources */, 80B6DF832142B44500BCB334 /* NSButton+WebCache.m in Sources */, 32D3CDCE21DDE87300C4DB49 /* UIImage+MemoryCacheCost.m in Sources */, + 329F1240223FAD3400B309FD /* SDInternalMacros.m in Sources */, 320CAE1B2086F50500CFFC80 /* SDWebImageError.m in Sources */, 32CF1C0D1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, 328BB6D32082581100760D6C /* SDMemoryCache.m in Sources */, diff --git a/SDWebImage/Private/SDImageAssetManager.m b/SDWebImage/Private/SDImageAssetManager.m index 1dc5503c..fa92e74f 100644 --- a/SDWebImage/Private/SDImageAssetManager.m +++ b/SDWebImage/Private/SDImageAssetManager.m @@ -7,6 +7,7 @@ */ #import "SDImageAssetManager.h" +#import "SDInternalMacros.h" static NSArray *SDBundlePreferredScales() { static NSArray *scales; diff --git a/SDWebImage/Private/SDInternalMacros.h b/SDWebImage/Private/SDInternalMacros.h new file mode 100644 index 00000000..22d73dfb --- /dev/null +++ b/SDWebImage/Private/SDInternalMacros.h @@ -0,0 +1,61 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "metamacros.h" + +#ifndef SD_LOCK +#define SD_LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); +#endif + +#ifndef SD_UNLOCK +#define SD_UNLOCK(lock) dispatch_semaphore_signal(lock); +#endif + +#ifndef weakify +#define weakify(...) \ +sd_keywordify \ +metamacro_foreach_cxt(sd_weakify_,, __weak, __VA_ARGS__) +#endif + +#ifndef strongify +#define strongify(...) \ +sd_keywordify \ +_Pragma("clang diagnostic push") \ +_Pragma("clang diagnostic ignored \"-Wshadow\"") \ +metamacro_foreach(sd_strongify_,, __VA_ARGS__) \ +_Pragma("clang diagnostic pop") +#endif + +#define sd_weakify_(INDEX, CONTEXT, VAR) \ +CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR); + +#define sd_strongify_(INDEX, VAR) \ +__strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_); + +#if DEBUG +#define sd_keywordify autoreleasepool {} +#else +#define sd_keywordify try {} @catch (...) {} +#endif + +#ifndef onExit +#define onExit \ +sd_keywordify \ +__strong sd_cleanupBlock_t metamacro_concat(sd_exitBlock_, __LINE__) __attribute__((cleanup(sd_executeCleanupBlock), unused)) = ^ +#endif + +typedef void (^sd_cleanupBlock_t)(void); + +#if defined(__cplusplus) +extern "C" { +#endif + void sd_executeCleanupBlock (__strong sd_cleanupBlock_t *block); +#if defined(__cplusplus) +} +#endif diff --git a/SDWebImage/Private/SDInternalMacros.m b/SDWebImage/Private/SDInternalMacros.m new file mode 100644 index 00000000..e4981af2 --- /dev/null +++ b/SDWebImage/Private/SDInternalMacros.m @@ -0,0 +1,13 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDInternalMacros.h" + +void sd_executeCleanupBlock (__strong sd_cleanupBlock_t *block) { + (*block)(); +} diff --git a/SDWebImage/Private/metamacros.h b/SDWebImage/Private/metamacros.h new file mode 100644 index 00000000..579756c6 --- /dev/null +++ b/SDWebImage/Private/metamacros.h @@ -0,0 +1,667 @@ +/** + * Macros for metaprogramming + * ExtendedC + * + * Copyright (C) 2012 Justin Spahr-Summers + * Released under the MIT license + */ + +#ifndef EXTC_METAMACROS_H +#define EXTC_METAMACROS_H + + +/** + * Executes one or more expressions (which may have a void type, such as a call + * to a function that returns no value) and always returns true. + */ +#define metamacro_exprify(...) \ + ((__VA_ARGS__), true) + +/** + * Returns a string representation of VALUE after full macro expansion. + */ +#define metamacro_stringify(VALUE) \ + metamacro_stringify_(VALUE) + +/** + * Returns A and B concatenated after full macro expansion. + */ +#define metamacro_concat(A, B) \ + metamacro_concat_(A, B) + +/** + * Returns the Nth variadic argument (starting from zero). At least + * N + 1 variadic arguments must be given. N must be between zero and twenty, + * inclusive. + */ +#define metamacro_at(N, ...) \ + metamacro_concat(metamacro_at, N)(__VA_ARGS__) + +/** + * Returns the number of arguments (up to twenty) provided to the macro. At + * least one argument must be provided. + * + * Inspired by P99: http://p99.gforge.inria.fr + */ +#define metamacro_argcount(...) \ + metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) + +/** + * Identical to #metamacro_foreach_cxt, except that no CONTEXT argument is + * given. Only the index and current argument will thus be passed to MACRO. + */ +#define metamacro_foreach(MACRO, SEP, ...) \ + metamacro_foreach_cxt(metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__) + +/** + * For each consecutive variadic argument (up to twenty), MACRO is passed the + * zero-based index of the current argument, CONTEXT, and then the argument + * itself. The results of adjoining invocations of MACRO are then separated by + * SEP. + * + * Inspired by P99: http://p99.gforge.inria.fr + */ +#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \ + metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__) + +/** + * Identical to #metamacro_foreach_cxt. This can be used when the former would + * fail due to recursive macro expansion. + */ +#define metamacro_foreach_cxt_recursive(MACRO, SEP, CONTEXT, ...) \ + metamacro_concat(metamacro_foreach_cxt_recursive, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__) + +/** + * In consecutive order, appends each variadic argument (up to twenty) onto + * BASE. The resulting concatenations are then separated by SEP. + * + * This is primarily useful to manipulate a list of macro invocations into instead + * invoking a different, possibly related macro. + */ +#define metamacro_foreach_concat(BASE, SEP, ...) \ + metamacro_foreach_cxt(metamacro_foreach_concat_iter, SEP, BASE, __VA_ARGS__) + +/** + * Iterates COUNT times, each time invoking MACRO with the current index + * (starting at zero) and CONTEXT. The results of adjoining invocations of MACRO + * are then separated by SEP. + * + * COUNT must be an integer between zero and twenty, inclusive. + */ +#define metamacro_for_cxt(COUNT, MACRO, SEP, CONTEXT) \ + metamacro_concat(metamacro_for_cxt, COUNT)(MACRO, SEP, CONTEXT) + +/** + * Returns the first argument given. At least one argument must be provided. + * + * This is useful when implementing a variadic macro, where you may have only + * one variadic argument, but no way to retrieve it (for example, because \c ... + * always needs to match at least one argument). + * + * @code + +#define varmacro(...) \ + metamacro_head(__VA_ARGS__) + + * @endcode + */ +#define metamacro_head(...) \ + metamacro_head_(__VA_ARGS__, 0) + +/** + * Returns every argument except the first. At least two arguments must be + * provided. + */ +#define metamacro_tail(...) \ + metamacro_tail_(__VA_ARGS__) + +/** + * Returns the first N (up to twenty) variadic arguments as a new argument list. + * At least N variadic arguments must be provided. + */ +#define metamacro_take(N, ...) \ + metamacro_concat(metamacro_take, N)(__VA_ARGS__) + +/** + * Removes the first N (up to twenty) variadic arguments from the given argument + * list. At least N variadic arguments must be provided. + */ +#define metamacro_drop(N, ...) \ + metamacro_concat(metamacro_drop, N)(__VA_ARGS__) + +/** + * Decrements VAL, which must be a number between zero and twenty, inclusive. + * + * This is primarily useful when dealing with indexes and counts in + * metaprogramming. + */ +#define metamacro_dec(VAL) \ + metamacro_at(VAL, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) + +/** + * Increments VAL, which must be a number between zero and twenty, inclusive. + * + * This is primarily useful when dealing with indexes and counts in + * metaprogramming. + */ +#define metamacro_inc(VAL) \ + metamacro_at(VAL, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21) + +/** + * If A is equal to B, the next argument list is expanded; otherwise, the + * argument list after that is expanded. A and B must be numbers between zero + * and twenty, inclusive. Additionally, B must be greater than or equal to A. + * + * @code + +// expands to true +metamacro_if_eq(0, 0)(true)(false) + +// expands to false +metamacro_if_eq(0, 1)(true)(false) + + * @endcode + * + * This is primarily useful when dealing with indexes and counts in + * metaprogramming. + */ +#define metamacro_if_eq(A, B) \ + metamacro_concat(metamacro_if_eq, A)(B) + +/** + * Identical to #metamacro_if_eq. This can be used when the former would fail + * due to recursive macro expansion. + */ +#define metamacro_if_eq_recursive(A, B) \ + metamacro_concat(metamacro_if_eq_recursive, A)(B) + +/** + * Returns 1 if N is an even number, or 0 otherwise. N must be between zero and + * twenty, inclusive. + * + * For the purposes of this test, zero is considered even. + */ +#define metamacro_is_even(N) \ + metamacro_at(N, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1) + +/** + * Returns the logical NOT of B, which must be the number zero or one. + */ +#define metamacro_not(B) \ + metamacro_at(B, 1, 0) + +// IMPLEMENTATION DETAILS FOLLOW! +// Do not write code that depends on anything below this line. +#define metamacro_stringify_(VALUE) # VALUE +#define metamacro_concat_(A, B) A ## B +#define metamacro_foreach_iter(INDEX, MACRO, ARG) MACRO(INDEX, ARG) +#define metamacro_head_(FIRST, ...) FIRST +#define metamacro_tail_(FIRST, ...) __VA_ARGS__ +#define metamacro_consume_(...) +#define metamacro_expand_(...) __VA_ARGS__ + +// implemented from scratch so that metamacro_concat() doesn't end up nesting +#define metamacro_foreach_concat_iter(INDEX, BASE, ARG) metamacro_foreach_concat_iter_(BASE, ARG) +#define metamacro_foreach_concat_iter_(BASE, ARG) BASE ## ARG + +// metamacro_at expansions +#define metamacro_at0(...) metamacro_head(__VA_ARGS__) +#define metamacro_at1(_0, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at2(_0, _1, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at3(_0, _1, _2, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at4(_0, _1, _2, _3, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at5(_0, _1, _2, _3, _4, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at6(_0, _1, _2, _3, _4, _5, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at7(_0, _1, _2, _3, _4, _5, _6, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at8(_0, _1, _2, _3, _4, _5, _6, _7, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at9(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at17(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at18(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at19(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, ...) metamacro_head(__VA_ARGS__) +#define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) metamacro_head(__VA_ARGS__) + +// metamacro_foreach_cxt expansions +#define metamacro_foreach_cxt0(MACRO, SEP, CONTEXT) +#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0) + +#define metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \ + metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) \ + SEP \ + MACRO(1, CONTEXT, _1) + +#define metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \ + metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \ + SEP \ + MACRO(2, CONTEXT, _2) + +#define metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ + metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \ + SEP \ + MACRO(3, CONTEXT, _3) + +#define metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ + metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ + SEP \ + MACRO(4, CONTEXT, _4) + +#define metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ + metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ + SEP \ + MACRO(5, CONTEXT, _5) + +#define metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ + metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ + SEP \ + MACRO(6, CONTEXT, _6) + +#define metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ + metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ + SEP \ + MACRO(7, CONTEXT, _7) + +#define metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ + metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ + SEP \ + MACRO(8, CONTEXT, _8) + +#define metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ + metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ + SEP \ + MACRO(9, CONTEXT, _9) + +#define metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ + metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ + SEP \ + MACRO(10, CONTEXT, _10) + +#define metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ + metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ + SEP \ + MACRO(11, CONTEXT, _11) + +#define metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ + metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ + SEP \ + MACRO(12, CONTEXT, _12) + +#define metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ + metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ + SEP \ + MACRO(13, CONTEXT, _13) + +#define metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ + metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ + SEP \ + MACRO(14, CONTEXT, _14) + +#define metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ + metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ + SEP \ + MACRO(15, CONTEXT, _15) + +#define metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ + metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ + SEP \ + MACRO(16, CONTEXT, _16) + +#define metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ + metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ + SEP \ + MACRO(17, CONTEXT, _17) + +#define metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ + metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ + SEP \ + MACRO(18, CONTEXT, _18) + +#define metamacro_foreach_cxt20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \ + metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ + SEP \ + MACRO(19, CONTEXT, _19) + +// metamacro_foreach_cxt_recursive expansions +#define metamacro_foreach_cxt_recursive0(MACRO, SEP, CONTEXT) +#define metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0) + +#define metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \ + metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) \ + SEP \ + MACRO(1, CONTEXT, _1) + +#define metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \ + metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \ + SEP \ + MACRO(2, CONTEXT, _2) + +#define metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ + metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \ + SEP \ + MACRO(3, CONTEXT, _3) + +#define metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ + metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ + SEP \ + MACRO(4, CONTEXT, _4) + +#define metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ + metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ + SEP \ + MACRO(5, CONTEXT, _5) + +#define metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ + metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ + SEP \ + MACRO(6, CONTEXT, _6) + +#define metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ + metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ + SEP \ + MACRO(7, CONTEXT, _7) + +#define metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ + metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ + SEP \ + MACRO(8, CONTEXT, _8) + +#define metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ + metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ + SEP \ + MACRO(9, CONTEXT, _9) + +#define metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ + metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ + SEP \ + MACRO(10, CONTEXT, _10) + +#define metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ + metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ + SEP \ + MACRO(11, CONTEXT, _11) + +#define metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ + metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ + SEP \ + MACRO(12, CONTEXT, _12) + +#define metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ + metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ + SEP \ + MACRO(13, CONTEXT, _13) + +#define metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ + metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ + SEP \ + MACRO(14, CONTEXT, _14) + +#define metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ + metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ + SEP \ + MACRO(15, CONTEXT, _15) + +#define metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ + metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ + SEP \ + MACRO(16, CONTEXT, _16) + +#define metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ + metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ + SEP \ + MACRO(17, CONTEXT, _17) + +#define metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ + metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ + SEP \ + MACRO(18, CONTEXT, _18) + +#define metamacro_foreach_cxt_recursive20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \ + metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ + SEP \ + MACRO(19, CONTEXT, _19) + +// metamacro_for_cxt expansions +#define metamacro_for_cxt0(MACRO, SEP, CONTEXT) +#define metamacro_for_cxt1(MACRO, SEP, CONTEXT) MACRO(0, CONTEXT) + +#define metamacro_for_cxt2(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt1(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(1, CONTEXT) + +#define metamacro_for_cxt3(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt2(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(2, CONTEXT) + +#define metamacro_for_cxt4(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt3(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(3, CONTEXT) + +#define metamacro_for_cxt5(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt4(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(4, CONTEXT) + +#define metamacro_for_cxt6(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt5(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(5, CONTEXT) + +#define metamacro_for_cxt7(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt6(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(6, CONTEXT) + +#define metamacro_for_cxt8(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt7(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(7, CONTEXT) + +#define metamacro_for_cxt9(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt8(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(8, CONTEXT) + +#define metamacro_for_cxt10(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt9(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(9, CONTEXT) + +#define metamacro_for_cxt11(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt10(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(10, CONTEXT) + +#define metamacro_for_cxt12(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt11(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(11, CONTEXT) + +#define metamacro_for_cxt13(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt12(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(12, CONTEXT) + +#define metamacro_for_cxt14(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt13(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(13, CONTEXT) + +#define metamacro_for_cxt15(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt14(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(14, CONTEXT) + +#define metamacro_for_cxt16(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt15(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(15, CONTEXT) + +#define metamacro_for_cxt17(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt16(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(16, CONTEXT) + +#define metamacro_for_cxt18(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt17(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(17, CONTEXT) + +#define metamacro_for_cxt19(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt18(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(18, CONTEXT) + +#define metamacro_for_cxt20(MACRO, SEP, CONTEXT) \ + metamacro_for_cxt19(MACRO, SEP, CONTEXT) \ + SEP \ + MACRO(19, CONTEXT) + +// metamacro_if_eq expansions +#define metamacro_if_eq0(VALUE) \ + metamacro_concat(metamacro_if_eq0_, VALUE) + +#define metamacro_if_eq0_0(...) __VA_ARGS__ metamacro_consume_ +#define metamacro_if_eq0_1(...) metamacro_expand_ +#define metamacro_if_eq0_2(...) metamacro_expand_ +#define metamacro_if_eq0_3(...) metamacro_expand_ +#define metamacro_if_eq0_4(...) metamacro_expand_ +#define metamacro_if_eq0_5(...) metamacro_expand_ +#define metamacro_if_eq0_6(...) metamacro_expand_ +#define metamacro_if_eq0_7(...) metamacro_expand_ +#define metamacro_if_eq0_8(...) metamacro_expand_ +#define metamacro_if_eq0_9(...) metamacro_expand_ +#define metamacro_if_eq0_10(...) metamacro_expand_ +#define metamacro_if_eq0_11(...) metamacro_expand_ +#define metamacro_if_eq0_12(...) metamacro_expand_ +#define metamacro_if_eq0_13(...) metamacro_expand_ +#define metamacro_if_eq0_14(...) metamacro_expand_ +#define metamacro_if_eq0_15(...) metamacro_expand_ +#define metamacro_if_eq0_16(...) metamacro_expand_ +#define metamacro_if_eq0_17(...) metamacro_expand_ +#define metamacro_if_eq0_18(...) metamacro_expand_ +#define metamacro_if_eq0_19(...) metamacro_expand_ +#define metamacro_if_eq0_20(...) metamacro_expand_ + +#define metamacro_if_eq1(VALUE) metamacro_if_eq0(metamacro_dec(VALUE)) +#define metamacro_if_eq2(VALUE) metamacro_if_eq1(metamacro_dec(VALUE)) +#define metamacro_if_eq3(VALUE) metamacro_if_eq2(metamacro_dec(VALUE)) +#define metamacro_if_eq4(VALUE) metamacro_if_eq3(metamacro_dec(VALUE)) +#define metamacro_if_eq5(VALUE) metamacro_if_eq4(metamacro_dec(VALUE)) +#define metamacro_if_eq6(VALUE) metamacro_if_eq5(metamacro_dec(VALUE)) +#define metamacro_if_eq7(VALUE) metamacro_if_eq6(metamacro_dec(VALUE)) +#define metamacro_if_eq8(VALUE) metamacro_if_eq7(metamacro_dec(VALUE)) +#define metamacro_if_eq9(VALUE) metamacro_if_eq8(metamacro_dec(VALUE)) +#define metamacro_if_eq10(VALUE) metamacro_if_eq9(metamacro_dec(VALUE)) +#define metamacro_if_eq11(VALUE) metamacro_if_eq10(metamacro_dec(VALUE)) +#define metamacro_if_eq12(VALUE) metamacro_if_eq11(metamacro_dec(VALUE)) +#define metamacro_if_eq13(VALUE) metamacro_if_eq12(metamacro_dec(VALUE)) +#define metamacro_if_eq14(VALUE) metamacro_if_eq13(metamacro_dec(VALUE)) +#define metamacro_if_eq15(VALUE) metamacro_if_eq14(metamacro_dec(VALUE)) +#define metamacro_if_eq16(VALUE) metamacro_if_eq15(metamacro_dec(VALUE)) +#define metamacro_if_eq17(VALUE) metamacro_if_eq16(metamacro_dec(VALUE)) +#define metamacro_if_eq18(VALUE) metamacro_if_eq17(metamacro_dec(VALUE)) +#define metamacro_if_eq19(VALUE) metamacro_if_eq18(metamacro_dec(VALUE)) +#define metamacro_if_eq20(VALUE) metamacro_if_eq19(metamacro_dec(VALUE)) + +// metamacro_if_eq_recursive expansions +#define metamacro_if_eq_recursive0(VALUE) \ + metamacro_concat(metamacro_if_eq_recursive0_, VALUE) + +#define metamacro_if_eq_recursive0_0(...) __VA_ARGS__ metamacro_consume_ +#define metamacro_if_eq_recursive0_1(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_2(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_3(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_4(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_5(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_6(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_7(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_8(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_9(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_10(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_11(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_12(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_13(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_14(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_15(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_16(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_17(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_18(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_19(...) metamacro_expand_ +#define metamacro_if_eq_recursive0_20(...) metamacro_expand_ + +#define metamacro_if_eq_recursive1(VALUE) metamacro_if_eq_recursive0(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive2(VALUE) metamacro_if_eq_recursive1(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive3(VALUE) metamacro_if_eq_recursive2(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive4(VALUE) metamacro_if_eq_recursive3(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive5(VALUE) metamacro_if_eq_recursive4(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive6(VALUE) metamacro_if_eq_recursive5(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive7(VALUE) metamacro_if_eq_recursive6(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive8(VALUE) metamacro_if_eq_recursive7(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive9(VALUE) metamacro_if_eq_recursive8(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive10(VALUE) metamacro_if_eq_recursive9(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive11(VALUE) metamacro_if_eq_recursive10(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive12(VALUE) metamacro_if_eq_recursive11(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive13(VALUE) metamacro_if_eq_recursive12(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive14(VALUE) metamacro_if_eq_recursive13(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive15(VALUE) metamacro_if_eq_recursive14(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive16(VALUE) metamacro_if_eq_recursive15(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive17(VALUE) metamacro_if_eq_recursive16(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive18(VALUE) metamacro_if_eq_recursive17(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive19(VALUE) metamacro_if_eq_recursive18(metamacro_dec(VALUE)) +#define metamacro_if_eq_recursive20(VALUE) metamacro_if_eq_recursive19(metamacro_dec(VALUE)) + +// metamacro_take expansions +#define metamacro_take0(...) +#define metamacro_take1(...) metamacro_head(__VA_ARGS__) +#define metamacro_take2(...) metamacro_head(__VA_ARGS__), metamacro_take1(metamacro_tail(__VA_ARGS__)) +#define metamacro_take3(...) metamacro_head(__VA_ARGS__), metamacro_take2(metamacro_tail(__VA_ARGS__)) +#define metamacro_take4(...) metamacro_head(__VA_ARGS__), metamacro_take3(metamacro_tail(__VA_ARGS__)) +#define metamacro_take5(...) metamacro_head(__VA_ARGS__), metamacro_take4(metamacro_tail(__VA_ARGS__)) +#define metamacro_take6(...) metamacro_head(__VA_ARGS__), metamacro_take5(metamacro_tail(__VA_ARGS__)) +#define metamacro_take7(...) metamacro_head(__VA_ARGS__), metamacro_take6(metamacro_tail(__VA_ARGS__)) +#define metamacro_take8(...) metamacro_head(__VA_ARGS__), metamacro_take7(metamacro_tail(__VA_ARGS__)) +#define metamacro_take9(...) metamacro_head(__VA_ARGS__), metamacro_take8(metamacro_tail(__VA_ARGS__)) +#define metamacro_take10(...) metamacro_head(__VA_ARGS__), metamacro_take9(metamacro_tail(__VA_ARGS__)) +#define metamacro_take11(...) metamacro_head(__VA_ARGS__), metamacro_take10(metamacro_tail(__VA_ARGS__)) +#define metamacro_take12(...) metamacro_head(__VA_ARGS__), metamacro_take11(metamacro_tail(__VA_ARGS__)) +#define metamacro_take13(...) metamacro_head(__VA_ARGS__), metamacro_take12(metamacro_tail(__VA_ARGS__)) +#define metamacro_take14(...) metamacro_head(__VA_ARGS__), metamacro_take13(metamacro_tail(__VA_ARGS__)) +#define metamacro_take15(...) metamacro_head(__VA_ARGS__), metamacro_take14(metamacro_tail(__VA_ARGS__)) +#define metamacro_take16(...) metamacro_head(__VA_ARGS__), metamacro_take15(metamacro_tail(__VA_ARGS__)) +#define metamacro_take17(...) metamacro_head(__VA_ARGS__), metamacro_take16(metamacro_tail(__VA_ARGS__)) +#define metamacro_take18(...) metamacro_head(__VA_ARGS__), metamacro_take17(metamacro_tail(__VA_ARGS__)) +#define metamacro_take19(...) metamacro_head(__VA_ARGS__), metamacro_take18(metamacro_tail(__VA_ARGS__)) +#define metamacro_take20(...) metamacro_head(__VA_ARGS__), metamacro_take19(metamacro_tail(__VA_ARGS__)) + +// metamacro_drop expansions +#define metamacro_drop0(...) __VA_ARGS__ +#define metamacro_drop1(...) metamacro_tail(__VA_ARGS__) +#define metamacro_drop2(...) metamacro_drop1(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop3(...) metamacro_drop2(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop4(...) metamacro_drop3(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop5(...) metamacro_drop4(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop6(...) metamacro_drop5(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop7(...) metamacro_drop6(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop8(...) metamacro_drop7(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop9(...) metamacro_drop8(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop10(...) metamacro_drop9(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop11(...) metamacro_drop10(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop12(...) metamacro_drop11(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop13(...) metamacro_drop12(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop14(...) metamacro_drop13(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop15(...) metamacro_drop14(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop16(...) metamacro_drop15(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop17(...) metamacro_drop16(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop18(...) metamacro_drop17(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop19(...) metamacro_drop18(metamacro_tail(__VA_ARGS__)) +#define metamacro_drop20(...) metamacro_drop19(metamacro_tail(__VA_ARGS__)) + +#endif \ No newline at end of file diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index 42c731d2..bf4dac83 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -13,6 +13,7 @@ #import "UIImage+Metadata.h" #import "NSImage+Compatibility.h" #import "SDWeakProxy.h" +#import "SDInternalMacros.h" #import #import diff --git a/SDWebImage/SDImageCodersManager.m b/SDWebImage/SDImageCodersManager.m index 77522cd4..8ad7e7b5 100644 --- a/SDWebImage/SDImageCodersManager.m +++ b/SDWebImage/SDImageCodersManager.m @@ -10,6 +10,7 @@ #import "SDImageIOCoder.h" #import "SDImageGIFCoder.h" #import "SDImageAPNGCoder.h" +#import "SDInternalMacros.h" @interface SDImageCodersManager () diff --git a/SDWebImage/SDImageLoadersManager.m b/SDWebImage/SDImageLoadersManager.m index 84461fce..406a3628 100644 --- a/SDWebImage/SDImageLoadersManager.m +++ b/SDWebImage/SDImageLoadersManager.m @@ -8,6 +8,7 @@ #import "SDImageLoadersManager.h" #import "SDWebImageDownloader.h" +#import "SDInternalMacros.h" @interface SDImageLoadersManager () diff --git a/SDWebImage/SDMemoryCache.m b/SDWebImage/SDMemoryCache.m index 8a03f117..c331fce3 100644 --- a/SDWebImage/SDMemoryCache.m +++ b/SDWebImage/SDMemoryCache.m @@ -9,6 +9,7 @@ #import "SDMemoryCache.h" #import "SDImageCacheConfig.h" #import "UIImage+MemoryCacheCost.h" +#import "SDInternalMacros.h" static void * SDMemoryCacheContext = &SDMemoryCacheContext; diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index 92bcf4ba..f47a248a 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -93,11 +93,3 @@ dispatch_async(dispatch_get_main_queue(), block);\ } #endif - -#ifndef SD_LOCK -#define SD_LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); -#endif - -#ifndef SD_UNLOCK -#define SD_UNLOCK(lock) dispatch_semaphore_signal(lock); -#endif diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 240e6372..c593ccf8 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -10,6 +10,7 @@ #import "SDWebImageDownloaderConfig.h" #import "SDWebImageDownloaderOperation.h" #import "SDWebImageError.h" +#import "SDInternalMacros.h" static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 5f1dd04e..0043a293 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -8,6 +8,7 @@ #import "SDWebImageDownloaderOperation.h" #import "SDWebImageError.h" +#import "SDInternalMacros.h" // iOS 8 Foundation.framework extern these symbol but the define is in CFNetwork.framework. We just fix this without import CFNetwork.framework #if (__IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0) diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 0a91d89d..ea059338 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -11,6 +11,7 @@ #import "SDWebImageDownloader.h" #import "UIImage+Metadata.h" #import "SDWebImageError.h" +#import "SDInternalMacros.h" static id _defaultImageCache; static id _defaultImageLoader; From e31a44f6a199c524fe71ae60e46ca5a3ca97feed Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 18 Mar 2019 19:35:53 +0800 Subject: [PATCH 326/361] Replace all the weak-strong dance code with @weakify and @strongify --- SDWebImage/SDImageCachesManager.m | 26 +++++++++++++-------- SDWebImage/SDWebImageDownloader.m | 12 +++++----- SDWebImage/SDWebImageDownloaderOperation.m | 2 +- SDWebImage/SDWebImageManager.m | 22 +++++++++--------- SDWebImage/UIView+WebCache.m | 27 +++++++++++----------- 5 files changed, 48 insertions(+), 41 deletions(-) diff --git a/SDWebImage/SDImageCachesManager.m b/SDWebImage/SDImageCachesManager.m index 1700737e..4c890423 100644 --- a/SDWebImage/SDImageCachesManager.m +++ b/SDWebImage/SDImageCachesManager.m @@ -8,6 +8,7 @@ #import "SDImageCachesManager.h" #import "SDImageCachesManagerOperation.h" +#import "SDInternalMacros.h" @implementation SDImageCachesManager @@ -407,8 +408,9 @@ } return; } - __weak typeof(self) wself = self; + @weakify(self); [cache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { + @strongify(self); if (operation.isCancelled) { // Cancelled return; @@ -427,7 +429,7 @@ return; } // Next - [wself serialQueryImageForKey:key options:options context:context completion:completionBlock enumerator:enumerator operation:operation]; + [self serialQueryImageForKey:key options:options context:context completion:completionBlock enumerator:enumerator operation:operation]; }]; } @@ -441,10 +443,11 @@ } return; } - __weak typeof(self) wself = self; + @weakify(self); [cache storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:^{ + @strongify(self); // Next - [wself serialStoreImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock enumerator:enumerator]; + [self serialStoreImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock enumerator:enumerator]; }]; } @@ -458,10 +461,11 @@ } return; } - __weak typeof(self) wself = self; + @weakify(self); [cache removeImageForKey:key cacheType:cacheType completion:^{ + @strongify(self); // Next - [wself serialRemoveImageForKey:key cacheType:cacheType completion:completionBlock enumerator:enumerator]; + [self serialRemoveImageForKey:key cacheType:cacheType completion:completionBlock enumerator:enumerator]; }]; } @@ -477,8 +481,9 @@ } return; } - __weak typeof(self) wself = self; + @weakify(self); [cache containsImageForKey:key cacheType:cacheType completion:^(SDImageCacheType containsCacheType) { + @strongify(self); if (operation.isCancelled) { // Cancelled return; @@ -497,7 +502,7 @@ return; } // Next - [wself serialContainsImageForKey:key cacheType:cacheType completion:completionBlock enumerator:enumerator operation:operation]; + [self serialContainsImageForKey:key cacheType:cacheType completion:completionBlock enumerator:enumerator operation:operation]; }]; } @@ -511,10 +516,11 @@ } return; } - __weak typeof(self) wself = self; + @weakify(self); [cache clearWithCacheType:cacheType completion:^{ + @strongify(self); // Next - [wself serialClearWithCacheType:cacheType completion:completionBlock enumerator:enumerator]; + [self serialClearWithCacheType:cacheType completion:completionBlock enumerator:enumerator]; }]; } diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index c593ccf8..b7c16861 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -203,15 +203,15 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; } return nil; } - __weak typeof(self) wself = self; + @weakify(self); operation.completionBlock = ^{ - __strong typeof(wself) sself = wself; - if (!sself) { + @strongify(self); + if (!self) { return; } - SD_LOCK(sself.operationsLock); - [sself.URLOperations removeObjectForKey:url]; - SD_UNLOCK(sself.operationsLock); + SD_LOCK(self.operationsLock); + [self.URLOperations removeObjectForKey:url]; + SD_UNLOCK(self.operationsLock); }; self.URLOperations[url] = operation; // Add operation to operation queue only after all configuration done according to Apple's doc. diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 0043a293..923919f7 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -142,7 +142,7 @@ typedef NSMutableDictionary SDCallbacksDictionary; Class UIApplicationClass = NSClassFromString(@"UIApplication"); BOOL hasApplication = UIApplicationClass && [UIApplicationClass respondsToSelector:@selector(sharedApplication)]; if (hasApplication && [self shouldContinueWhenAppEntersBackground]) { - __weak __typeof__ (self) wself = self; + __weak typeof(self) wself = self; UIApplication * app = [UIApplicationClass performSelector:@selector(sharedApplication)]; self.backgroundTaskId = [app beginBackgroundTaskWithExpirationHandler:^{ [wself cancel]; diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index ea059338..e5428dd4 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -189,15 +189,15 @@ static id _defaultImageLoader; if (shouldQueryCache) { id cacheKeyFilter = context[SDWebImageContextCacheKeyFilter]; NSString *key = [self cacheKeyForURL:url cacheKeyFilter:cacheKeyFilter]; - __weak SDWebImageCombinedOperation *weakOperation = operation; + @weakify(operation); operation.cacheOperation = [self.imageCache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable cachedImage, NSData * _Nullable cachedData, SDImageCacheType cacheType) { - __strong __typeof(weakOperation) strongOperation = weakOperation; - if (!strongOperation || strongOperation.isCancelled) { - [self safelyRemoveOperationFromRunning:strongOperation]; + @strongify(operation); + if (!operation || operation.isCancelled) { + [self safelyRemoveOperationFromRunning:operation]; return; } // Continue download process - [self callDownloadProcessForOperation:strongOperation url:url options:options context:context cachedImage:cachedImage cachedData:cachedData cacheType:cacheType progress:progressBlock completed:completedBlock]; + [self callDownloadProcessForOperation:operation url:url options:options context:context cachedImage:cachedImage cachedData:cachedData cacheType:cacheType progress:progressBlock completed:completedBlock]; }]; } else { // Continue download process @@ -237,17 +237,17 @@ static id _defaultImageLoader; } // `SDWebImageCombinedOperation` -> `SDWebImageDownloadToken` -> `downloadOperationCancelToken`, which is a `SDCallbacksDictionary` and retain the completed block below, so we need weak-strong again to avoid retain cycle - __weak typeof(operation) weakOperation = operation; + @weakify(operation); operation.loaderOperation = [self.imageLoader loadImageWithURL:url options:options context:context progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { - __strong typeof(weakOperation) strongOperation = weakOperation; - if (!strongOperation || strongOperation.isCancelled) { + @strongify(operation); + if (!operation || operation.isCancelled) { // Do nothing if the operation was cancelled // See #699 for more details // if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data } else if (cachedImage && options & SDWebImageRefreshCached && [error.domain isEqualToString:SDWebImageErrorDomain] && error.code == SDWebImageErrorCacheNotModified) { // Image refresh hit the NSURLCache cache, do not call the completion block } else if (error) { - [self callCompletionBlockForOperation:strongOperation completion:completedBlock error:error url:url]; + [self callCompletionBlockForOperation:operation completion:completedBlock error:error url:url]; BOOL shouldBlockFailedURL = [self shouldBlockFailedURLWithURL:url error:error]; if (shouldBlockFailedURL) { @@ -262,11 +262,11 @@ static id _defaultImageLoader; SD_UNLOCK(self.failedURLsLock); } - [self callStoreCacheProcessForOperation:strongOperation url:url options:options context:context downloadedImage:downloadedImage downloadedData:downloadedData finished:finished progress:progressBlock completed:completedBlock]; + [self callStoreCacheProcessForOperation:operation url:url options:options context:context downloadedImage:downloadedImage downloadedData:downloadedData finished:finished progress:progressBlock completed:completedBlock]; } if (finished) { - [self safelyRemoveOperationFromRunning:strongOperation]; + [self safelyRemoveOperationFromRunning:operation]; } }]; } else if (cachedImage) { diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 69ef9b27..38b9ac55 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -10,6 +10,7 @@ #import "objc/runtime.h" #import "UIView+WebCacheOperation.h" #import "SDWebImageError.h" +#import "SDInternalMacros.h" const int64_t SDWebImageProgressUnitCountUnknown = 1LL; @@ -73,10 +74,10 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; manager = [SDWebImageManager sharedManager]; } - __weak __typeof(self)wself = self; + @weakify(self); SDImageLoaderProgressBlock combinedProgressBlock = ^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { - __strong __typeof (wself) sself = wself; - NSProgress *imageProgress = sself.sd_imageProgress; + @strongify(self); + NSProgress *imageProgress = self.sd_imageProgress; imageProgress.totalUnitCount = expectedSize; imageProgress.completedUnitCount = receivedSize; #if SD_UIKIT || SD_MAC @@ -92,12 +93,12 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; } }; id operation = [manager loadImageWithURL:url options:options context:context progress:combinedProgressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { - __strong __typeof (wself) sself = wself; - if (!sself) { return; } + @strongify(self); + if (!self) { return; } // if the progress not been updated, mark it to complete state - if (finished && !error && sself.sd_imageProgress.totalUnitCount == 0 && sself.sd_imageProgress.completedUnitCount == 0) { - sself.sd_imageProgress.totalUnitCount = SDWebImageProgressUnitCountUnknown; - sself.sd_imageProgress.completedUnitCount = SDWebImageProgressUnitCountUnknown; + if (finished && !error && self.sd_imageProgress.totalUnitCount == 0 && self.sd_imageProgress.completedUnitCount == 0) { + self.sd_imageProgress.totalUnitCount = SDWebImageProgressUnitCountUnknown; + self.sd_imageProgress.completedUnitCount = SDWebImageProgressUnitCountUnknown; } #if SD_UIKIT || SD_MAC @@ -111,9 +112,9 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; BOOL shouldNotSetImage = ((image && (options & SDWebImageAvoidAutoSetImage)) || (!image && !(options & SDWebImageDelayPlaceholder))); SDWebImageNoParamsBlock callCompletedBlockClojure = ^{ - if (!sself) { return; } + if (!self) { return; } if (!shouldNotSetImage) { - [sself sd_setNeedsLayout]; + [self sd_setNeedsLayout]; } if (completedBlock && shouldCallCompletedBlock) { completedBlock(image, data, error, cacheType, finished, url); @@ -144,14 +145,14 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; // check whether we should use the image transition SDWebImageTransition *transition = nil; if (finished && (options & SDWebImageForceTransition || cacheType == SDImageCacheTypeNone)) { - transition = sself.sd_imageTransition; + transition = self.sd_imageTransition; } #endif dispatch_main_async_safe(^{ #if SD_UIKIT || SD_MAC - [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL]; + [self sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL]; #else - [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock cacheType:cacheType imageURL:imageURL]; + [self sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock cacheType:cacheType imageURL:imageURL]; #endif callCompletedBlockClojure(); }); From c6247d2d63d9becda4d92b705b140ed50a6d008b Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 19 Mar 2019 13:15:36 +0800 Subject: [PATCH 327/361] Using pch for the internal macros, to avoid each implementation files import this macro --- Configs/App-Shared.xcconfig | 5 ++++- Configs/Module-Shared.xcconfig | 3 +++ SDWebImage.podspec | 1 + SDWebImage/Private/SDImageAssetManager.m | 1 - SDWebImage/Private/metamacros.h | 2 +- SDWebImage/SDAnimatedImageView.m | 1 - SDWebImage/SDImageCachesManager.m | 1 - SDWebImage/SDImageCodersManager.m | 1 - SDWebImage/SDImageLoadersManager.m | 1 - SDWebImage/SDMemoryCache.m | 1 - SDWebImage/SDWebImageDownloader.m | 1 - SDWebImage/SDWebImageDownloaderOperation.m | 1 - SDWebImage/SDWebImageManager.m | 1 - SDWebImage/UIView+WebCache.m | 1 - WebImage/SDWebImage.pch | 10 ++++++++++ 15 files changed, 19 insertions(+), 12 deletions(-) create mode 100644 WebImage/SDWebImage.pch diff --git a/Configs/App-Shared.xcconfig b/Configs/App-Shared.xcconfig index 351625b0..57760e6c 100644 --- a/Configs/App-Shared.xcconfig +++ b/Configs/App-Shared.xcconfig @@ -7,4 +7,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon // The compiler to use for C, C++, and Objective-C. -GCC_VERSION = \ No newline at end of file +GCC_VERSION = + +// Implicitly include the named header. The path given should either be a project relative path or an absolute path. +GCC_PREFIX_HEADER = diff --git a/Configs/Module-Shared.xcconfig b/Configs/Module-Shared.xcconfig index 9bacfd5d..f2ba5f80 100644 --- a/Configs/Module-Shared.xcconfig +++ b/Configs/Module-Shared.xcconfig @@ -228,3 +228,6 @@ VERSIONING_SYSTEM = apple-generic // Code will load on this and later versions of watchOS. Framework APIs that are unavailable in earlier versions will be weak-linked; your code should check for null function pointers or specific system versions before calling newer APIs. WATCHOS_DEPLOYMENT_TARGET = 2.0 + +// Implicitly include the named header. The path given should either be a project relative path or an absolute path. +GCC_PREFIX_HEADER = WebImage/SDWebImage.pch diff --git a/SDWebImage.podspec b/SDWebImage.podspec index 8f282506..8b376bba 100644 --- a/SDWebImage.podspec +++ b/SDWebImage.podspec @@ -31,6 +31,7 @@ Pod::Spec.new do |s| core.source_files = 'SDWebImage/*.{h,m}', 'WebImage/SDWebImage.h', 'SDWebImage/Private/*.{h,m}' core.exclude_files = 'SDWebImage/MapKit/*.{h,m}' core.private_header_files = 'SDWebImage/Private/*.h' + core.prefix_header_contents = '#import "SDInternalMacros.h"' end s.subspec 'MapKit' do |mk| diff --git a/SDWebImage/Private/SDImageAssetManager.m b/SDWebImage/Private/SDImageAssetManager.m index fa92e74f..1dc5503c 100644 --- a/SDWebImage/Private/SDImageAssetManager.m +++ b/SDWebImage/Private/SDImageAssetManager.m @@ -7,7 +7,6 @@ */ #import "SDImageAssetManager.h" -#import "SDInternalMacros.h" static NSArray *SDBundlePreferredScales() { static NSArray *scales; diff --git a/SDWebImage/Private/metamacros.h b/SDWebImage/Private/metamacros.h index 579756c6..dd90d99b 100644 --- a/SDWebImage/Private/metamacros.h +++ b/SDWebImage/Private/metamacros.h @@ -664,4 +664,4 @@ metamacro_if_eq(0, 1)(true)(false) #define metamacro_drop19(...) metamacro_drop18(metamacro_tail(__VA_ARGS__)) #define metamacro_drop20(...) metamacro_drop19(metamacro_tail(__VA_ARGS__)) -#endif \ No newline at end of file +#endif diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index bf4dac83..42c731d2 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -13,7 +13,6 @@ #import "UIImage+Metadata.h" #import "NSImage+Compatibility.h" #import "SDWeakProxy.h" -#import "SDInternalMacros.h" #import #import diff --git a/SDWebImage/SDImageCachesManager.m b/SDWebImage/SDImageCachesManager.m index 4c890423..fd31cd9f 100644 --- a/SDWebImage/SDImageCachesManager.m +++ b/SDWebImage/SDImageCachesManager.m @@ -8,7 +8,6 @@ #import "SDImageCachesManager.h" #import "SDImageCachesManagerOperation.h" -#import "SDInternalMacros.h" @implementation SDImageCachesManager diff --git a/SDWebImage/SDImageCodersManager.m b/SDWebImage/SDImageCodersManager.m index 8ad7e7b5..77522cd4 100644 --- a/SDWebImage/SDImageCodersManager.m +++ b/SDWebImage/SDImageCodersManager.m @@ -10,7 +10,6 @@ #import "SDImageIOCoder.h" #import "SDImageGIFCoder.h" #import "SDImageAPNGCoder.h" -#import "SDInternalMacros.h" @interface SDImageCodersManager () diff --git a/SDWebImage/SDImageLoadersManager.m b/SDWebImage/SDImageLoadersManager.m index 406a3628..84461fce 100644 --- a/SDWebImage/SDImageLoadersManager.m +++ b/SDWebImage/SDImageLoadersManager.m @@ -8,7 +8,6 @@ #import "SDImageLoadersManager.h" #import "SDWebImageDownloader.h" -#import "SDInternalMacros.h" @interface SDImageLoadersManager () diff --git a/SDWebImage/SDMemoryCache.m b/SDWebImage/SDMemoryCache.m index c331fce3..8a03f117 100644 --- a/SDWebImage/SDMemoryCache.m +++ b/SDWebImage/SDMemoryCache.m @@ -9,7 +9,6 @@ #import "SDMemoryCache.h" #import "SDImageCacheConfig.h" #import "UIImage+MemoryCacheCost.h" -#import "SDInternalMacros.h" static void * SDMemoryCacheContext = &SDMemoryCacheContext; diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index b7c16861..358b0d28 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -10,7 +10,6 @@ #import "SDWebImageDownloaderConfig.h" #import "SDWebImageDownloaderOperation.h" #import "SDWebImageError.h" -#import "SDInternalMacros.h" static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 923919f7..39aad9cd 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -8,7 +8,6 @@ #import "SDWebImageDownloaderOperation.h" #import "SDWebImageError.h" -#import "SDInternalMacros.h" // iOS 8 Foundation.framework extern these symbol but the define is in CFNetwork.framework. We just fix this without import CFNetwork.framework #if (__IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0) diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index e5428dd4..35baa08c 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -11,7 +11,6 @@ #import "SDWebImageDownloader.h" #import "UIImage+Metadata.h" #import "SDWebImageError.h" -#import "SDInternalMacros.h" static id _defaultImageCache; static id _defaultImageLoader; diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 38b9ac55..289c90e3 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -10,7 +10,6 @@ #import "objc/runtime.h" #import "UIView+WebCacheOperation.h" #import "SDWebImageError.h" -#import "SDInternalMacros.h" const int64_t SDWebImageProgressUnitCountUnknown = 1LL; diff --git a/WebImage/SDWebImage.pch b/WebImage/SDWebImage.pch new file mode 100644 index 00000000..62e1726a --- /dev/null +++ b/WebImage/SDWebImage.pch @@ -0,0 +1,10 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Florent Vilmart + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDInternalMacros.h" From e702214f826813da4cc9482fa7d9698278dececa Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 19 Mar 2019 13:21:29 +0800 Subject: [PATCH 328/361] Move the dispatch_main_async_safe into internal macros, since it's used in implementation files but not headers SDWebImageCompat.h should only contain the macros support used in header --- SDWebImage/Private/SDInternalMacros.h | 9 +++++++++ SDWebImage/SDWebImageCompat.h | 9 --------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/SDWebImage/Private/SDInternalMacros.h b/SDWebImage/Private/SDInternalMacros.h index 22d73dfb..3bb8442a 100644 --- a/SDWebImage/Private/SDInternalMacros.h +++ b/SDWebImage/Private/SDInternalMacros.h @@ -9,6 +9,15 @@ #import #import "metamacros.h" +#ifndef dispatch_main_async_safe +#define dispatch_main_async_safe(block)\ +if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(dispatch_get_main_queue())) {\ + block();\ +} else {\ + dispatch_async(dispatch_get_main_queue(), block);\ +} +#endif + #ifndef SD_LOCK #define SD_LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); #endif diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index f47a248a..54ec168b 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -84,12 +84,3 @@ #ifndef NS_OPTIONS #define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type #endif - -#ifndef dispatch_main_async_safe -#define dispatch_main_async_safe(block)\ - if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(dispatch_get_main_queue())) {\ - block();\ - } else {\ - dispatch_async(dispatch_get_main_queue(), block);\ - } -#endif From a065fa2379a3e174eebf38f2985263a5dc9a0b21 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 19 Mar 2019 13:26:21 +0800 Subject: [PATCH 329/361] Rename pch file with Prefix.pch, make it easy to distinguish from the umbrella headers --- Configs/Module-Shared.xcconfig | 2 +- WebImage/{SDWebImage.pch => SDWebImage-Prefix.pch} | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) rename WebImage/{SDWebImage.pch => SDWebImage-Prefix.pch} (91%) diff --git a/Configs/Module-Shared.xcconfig b/Configs/Module-Shared.xcconfig index f2ba5f80..71bccf54 100644 --- a/Configs/Module-Shared.xcconfig +++ b/Configs/Module-Shared.xcconfig @@ -230,4 +230,4 @@ VERSIONING_SYSTEM = apple-generic WATCHOS_DEPLOYMENT_TARGET = 2.0 // Implicitly include the named header. The path given should either be a project relative path or an absolute path. -GCC_PREFIX_HEADER = WebImage/SDWebImage.pch +GCC_PREFIX_HEADER = WebImage/SDWebImage-Prefix.pch diff --git a/WebImage/SDWebImage.pch b/WebImage/SDWebImage-Prefix.pch similarity index 91% rename from WebImage/SDWebImage.pch rename to WebImage/SDWebImage-Prefix.pch index 62e1726a..badb42c3 100644 --- a/WebImage/SDWebImage.pch +++ b/WebImage/SDWebImage-Prefix.pch @@ -1,7 +1,6 @@ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey - * (c) Florent Vilmart * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. From c6fe902a30deb063e5f8e1a26300c34772c26278 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 19 Mar 2019 14:19:29 +0800 Subject: [PATCH 330/361] Fix the SDWebImage Test project using the framework xcconfig, should ignore the prefix header --- Configs/Test-Debug.xcconfig | 5 +++++ Configs/Test-Release.xcconfig | 5 +++++ Configs/Test-Shared.xcconfig | 7 ++++++ .../project.pbxproj | 22 +++++++++++++++++-- 4 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 Configs/Test-Debug.xcconfig create mode 100644 Configs/Test-Release.xcconfig create mode 100644 Configs/Test-Shared.xcconfig diff --git a/Configs/Test-Debug.xcconfig b/Configs/Test-Debug.xcconfig new file mode 100644 index 00000000..d3c686e2 --- /dev/null +++ b/Configs/Test-Debug.xcconfig @@ -0,0 +1,5 @@ +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +#include "Module-Debug.xcconfig" +#include "Test-Shared.xcconfig" diff --git a/Configs/Test-Release.xcconfig b/Configs/Test-Release.xcconfig new file mode 100644 index 00000000..b3683aed --- /dev/null +++ b/Configs/Test-Release.xcconfig @@ -0,0 +1,5 @@ +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +#include "Module-Release.xcconfig" +#include "Test-Shared.xcconfig" diff --git a/Configs/Test-Shared.xcconfig b/Configs/Test-Shared.xcconfig new file mode 100644 index 00000000..f8229336 --- /dev/null +++ b/Configs/Test-Shared.xcconfig @@ -0,0 +1,7 @@ +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +#include "Module-Shared.xcconfig" + +// Implicitly include the named header. The path given should either be a project relative path or an absolute path. +GCC_PREFIX_HEADER = diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 30a05d56..e53ee549 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -22,6 +22,12 @@ 327054E3206CEFF3006EA328 /* TestImageAnimated.apng in Resources */ = {isa = PBXBuildFile; fileRef = 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */; }; 327A418C211D660600495442 /* TestImage.heic in Resources */ = {isa = PBXBuildFile; fileRef = 327A418B211D660600495442 /* TestImage.heic */; }; 327A418D211D660600495442 /* TestImage.heic in Resources */ = {isa = PBXBuildFile; fileRef = 327A418B211D660600495442 /* TestImage.heic */; }; + 328BAF292240C08E00FC70DD /* Test-Shared.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 328BAF262240C08E00FC70DD /* Test-Shared.xcconfig */; }; + 328BAF2A2240C08E00FC70DD /* Test-Shared.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 328BAF262240C08E00FC70DD /* Test-Shared.xcconfig */; }; + 328BAF2B2240C08E00FC70DD /* Test-Release.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 328BAF272240C08E00FC70DD /* Test-Release.xcconfig */; }; + 328BAF2C2240C08E00FC70DD /* Test-Release.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 328BAF272240C08E00FC70DD /* Test-Release.xcconfig */; }; + 328BAF2D2240C08E00FC70DD /* Test-Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 328BAF282240C08E00FC70DD /* Test-Debug.xcconfig */; }; + 328BAF2E2240C08E00FC70DD /* Test-Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 328BAF282240C08E00FC70DD /* Test-Debug.xcconfig */; }; 328BB6DD20825E9800760D6C /* SDWebImageTestCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6DC20825E9800760D6C /* SDWebImageTestCache.m */; }; 328BB6DE20825E9800760D6C /* SDWebImageTestCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6DC20825E9800760D6C /* SDWebImageTestCache.m */; }; 32905E64211D786E00460FCF /* TestImage.heif in Resources */ = {isa = PBXBuildFile; fileRef = 32905E63211D786E00460FCF /* TestImage.heif */; }; @@ -78,6 +84,9 @@ 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestTransformer.m; sourceTree = ""; }; 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageAnimated.apng; sourceTree = ""; }; 327A418B211D660600495442 /* TestImage.heic */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImage.heic; sourceTree = ""; }; + 328BAF262240C08E00FC70DD /* Test-Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Test-Shared.xcconfig"; sourceTree = ""; }; + 328BAF272240C08E00FC70DD /* Test-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Test-Release.xcconfig"; sourceTree = ""; }; + 328BAF282240C08E00FC70DD /* Test-Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Test-Debug.xcconfig"; sourceTree = ""; }; 328BB6DB20825E9800760D6C /* SDWebImageTestCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestCache.h; sourceTree = ""; }; 328BB6DC20825E9800760D6C /* SDWebImageTestCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestCache.m; sourceTree = ""; }; 32905E63211D786E00460FCF /* TestImage.heif */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImage.heif; sourceTree = ""; }; @@ -253,6 +262,9 @@ EADD19EC219915E300804BB0 /* Module-Debug.xcconfig */, EADD19E9219915E300804BB0 /* Module-Release.xcconfig */, EADD19EE219915E300804BB0 /* Module-Shared.xcconfig */, + 328BAF282240C08E00FC70DD /* Test-Debug.xcconfig */, + 328BAF272240C08E00FC70DD /* Test-Release.xcconfig */, + 328BAF262240C08E00FC70DD /* Test-Shared.xcconfig */, ); name = Configs; path = ../Configs; @@ -338,12 +350,15 @@ files = ( 327054E3206CEFF3006EA328 /* TestImageAnimated.apng in Resources */, 32B99EA3203B31360017FD66 /* TestImage.gif in Resources */, + 328BAF2C2240C08E00FC70DD /* Test-Release.xcconfig in Resources */, + 328BAF2E2240C08E00FC70DD /* Test-Debug.xcconfig in Resources */, 32B99EA4203B31360017FD66 /* TestImage.jpg in Resources */, 32B99EA6203B31360017FD66 /* TestImage.png in Resources */, 32B99EA2203B31360017FD66 /* MonochromeTestImage.jpg in Resources */, 32905E65211D786E00460FCF /* TestImage.heif in Resources */, 327A418D211D660600495442 /* TestImage.heic in Resources */, 32B99EA5203B31360017FD66 /* TestImageLarge.jpg in Resources */, + 328BAF2A2240C08E00FC70DD /* Test-Shared.xcconfig in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -351,10 +366,13 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 328BAF2B2240C08E00FC70DD /* Test-Release.xcconfig in Resources */, 327A418C211D660600495442 /* TestImage.heic in Resources */, + 328BAF292240C08E00FC70DD /* Test-Shared.xcconfig in Resources */, 5F7F38AD1AE2A77A00B0E330 /* TestImage.jpg in Resources */, 32905E64211D786E00460FCF /* TestImage.heif in Resources */, 43828A451DA67F9900000E62 /* TestImageLarge.jpg in Resources */, + 328BAF2D2240C08E00FC70DD /* Test-Debug.xcconfig in Resources */, 433BBBB71D7EF8200086B6E9 /* TestImage.gif in Resources */, DA248D61195472AA00390AB0 /* InfoPlist.strings in Resources */, 433BBBB91D7EF8260086B6E9 /* TestImage.png in Resources */, @@ -543,14 +561,14 @@ }; DA248D4A1954721A00390AB0 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = EADD19EC219915E300804BB0 /* Module-Debug.xcconfig */; + baseConfigurationReference = 328BAF282240C08E00FC70DD /* Test-Debug.xcconfig */; buildSettings = { }; name = Debug; }; DA248D4B1954721A00390AB0 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = EADD19E9219915E300804BB0 /* Module-Release.xcconfig */; + baseConfigurationReference = 328BAF272240C08E00FC70DD /* Test-Release.xcconfig */; buildSettings = { }; name = Release; From 08c6e2290698e80f9d0e046b39db2317f32b5760 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 21 Mar 2019 19:37:18 +0800 Subject: [PATCH 331/361] Rename metamacro.h filename with SDmetamacro.h --- SDWebImage.xcodeproj/project.pbxproj | 12 ++++++------ SDWebImage/Private/SDInternalMacros.h | 2 +- SDWebImage/Private/{metamacros.h => SDmetamacros.h} | 0 3 files changed, 7 insertions(+), 7 deletions(-) rename SDWebImage/Private/{metamacros.h => SDmetamacros.h} (100%) diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 45536ee5..ef29fba9 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -115,8 +115,8 @@ 329A185B1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; 329A185F1FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; 329A18611FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; - 329F1236223FAA3B00B309FD /* metamacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 329F1235223FAA3B00B309FD /* metamacros.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 329F1237223FAA3B00B309FD /* metamacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 329F1235223FAA3B00B309FD /* metamacros.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 329F1236223FAA3B00B309FD /* SDmetamacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 329F1235223FAA3B00B309FD /* SDmetamacros.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 329F1237223FAA3B00B309FD /* SDmetamacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 329F1235223FAA3B00B309FD /* SDmetamacros.h */; settings = {ATTRIBUTES = (Private, ); }; }; 329F1240223FAD3400B309FD /* SDInternalMacros.m in Sources */ = {isa = PBXBuildFile; fileRef = 329F123E223FAD3400B309FD /* SDInternalMacros.m */; }; 329F1241223FAD3400B309FD /* SDInternalMacros.m in Sources */ = {isa = PBXBuildFile; fileRef = 329F123E223FAD3400B309FD /* SDInternalMacros.m */; }; 329F1242223FAD3400B309FD /* SDInternalMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 329F123F223FAD3400B309FD /* SDInternalMacros.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -315,7 +315,7 @@ 3290FA031FA478AF0047D20C /* SDImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageFrame.m; sourceTree = ""; }; 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Metadata.h"; sourceTree = ""; }; 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Metadata.m"; sourceTree = ""; }; - 329F1235223FAA3B00B309FD /* metamacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metamacros.h; sourceTree = ""; }; + 329F1235223FAA3B00B309FD /* SDmetamacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDmetamacros.h; sourceTree = ""; }; 329F123E223FAD3400B309FD /* SDInternalMacros.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDInternalMacros.m; sourceTree = ""; }; 329F123F223FAD3400B309FD /* SDInternalMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDInternalMacros.h; sourceTree = ""; }; 32B5CC5E222F89C2005EB74E /* SDAsyncBlockOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDAsyncBlockOperation.h; sourceTree = ""; }; @@ -508,7 +508,7 @@ 325C46252233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m */, 329F123F223FAD3400B309FD /* SDInternalMacros.h */, 329F123E223FAD3400B309FD /* SDInternalMacros.m */, - 329F1235223FAA3B00B309FD /* metamacros.h */, + 329F1235223FAA3B00B309FD /* SDmetamacros.h */, ); path = Private; sourceTree = ""; @@ -727,7 +727,7 @@ 80B6DF842142B44600BCB334 /* NSButton+WebCache.h in Headers */, 43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 3290FA061FA478AF0047D20C /* SDImageFrame.h in Headers */, - 329F1237223FAA3B00B309FD /* metamacros.h in Headers */, + 329F1237223FAA3B00B309FD /* SDmetamacros.h in Headers */, 324DF4B6200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 807A122A1F89636300EC2A9B /* SDImageCodersManager.h in Headers */, 4A2CAE211AB4BB7000B6BC39 /* SDWebImageManager.h in Headers */, @@ -794,7 +794,7 @@ 80B6DF852142B44700BCB334 /* NSButton+WebCache.h in Headers */, 807A12281F89636300EC2A9B /* SDImageCodersManager.h in Headers */, 32B9B537206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, - 329F1236223FAA3B00B309FD /* metamacros.h in Headers */, + 329F1236223FAA3B00B309FD /* SDmetamacros.h in Headers */, 32484775201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 321E60941F38E8ED00405457 /* SDImageIOCoder.h in Headers */, 329A18591FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, diff --git a/SDWebImage/Private/SDInternalMacros.h b/SDWebImage/Private/SDInternalMacros.h index 3bb8442a..9e0dee3a 100644 --- a/SDWebImage/Private/SDInternalMacros.h +++ b/SDWebImage/Private/SDInternalMacros.h @@ -7,7 +7,7 @@ */ #import -#import "metamacros.h" +#import "SDmetamacros.h" #ifndef dispatch_main_async_safe #define dispatch_main_async_safe(block)\ diff --git a/SDWebImage/Private/metamacros.h b/SDWebImage/Private/SDmetamacros.h similarity index 100% rename from SDWebImage/Private/metamacros.h rename to SDWebImage/Private/SDmetamacros.h From 57ad6853ed4d62487c679c6542cef7c8befefae0 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 21 Mar 2019 19:46:25 +0800 Subject: [PATCH 332/361] Update SDWebImagePrefetcher weak-strong dance code into weakify && strongify --- SDWebImage/SDWebImagePrefetcher.m | 63 +++++++++++++++---------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index 0540bab4..e141e24e 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -107,39 +107,38 @@ - (void)startPrefetchWithToken:(SDWebImagePrefetchToken * _Nonnull)token { NSPointerArray *operations = token.loadOperations; for (NSURL *url in token.urls) { - __weak typeof(self) wself = self; + @weakify(self); SDAsyncBlockOperation *prefetchOperation = [SDAsyncBlockOperation blockOperationWithBlock:^(SDAsyncBlockOperation * _Nonnull asyncOperation) { - __strong typeof(wself) strongSelf = wself; - if (!strongSelf || asyncOperation.isCancelled) { - return; - } - id operation = [strongSelf.manager loadImageWithURL:url options:strongSelf.options context:strongSelf.context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { - __strong typeof(wself) sself = wself; - if (!sself) { - return; - } - if (!finished) { - return; - } - - atomic_fetch_add_explicit(&(token->_finishedCount), 1, memory_order_relaxed); - if (error) { - // Add last failed - atomic_fetch_add_explicit(&(token->_skippedCount), 1, memory_order_relaxed); - } - - // Current operation finished - [sself callProgressBlockForToken:token imageURL:imageURL]; - - if (atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed) == token->_totalCount) { - // All finished - if (!atomic_flag_test_and_set_explicit(&(token->_isAllFinished), memory_order_relaxed)) { - [sself callCompletionBlockForToken:token]; - [sself removeRunningToken:token]; - } - } - [asyncOperation complete]; - }]; + @strongify(self); + if (!self || asyncOperation.isCancelled) { + return; + } + id operation = [self.manager loadImageWithURL:url options:self.options context:self.context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + @strongify(self); + if (!self) { + return; + } + if (!finished) { + return; + } + atomic_fetch_add_explicit(&(token->_finishedCount), 1, memory_order_relaxed); + if (error) { + // Add last failed + atomic_fetch_add_explicit(&(token->_skippedCount), 1, memory_order_relaxed); + } + + // Current operation finished + [self callProgressBlockForToken:token imageURL:imageURL]; + + if (atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed) == token->_totalCount) { + // All finished + if (!atomic_flag_test_and_set_explicit(&(token->_isAllFinished), memory_order_relaxed)) { + [self callCompletionBlockForToken:token]; + [self removeRunningToken:token]; + } + } + [asyncOperation complete]; + }]; NSAssert(operation != nil, @"Operation should not be nil, [SDWebImageManager loadImageWithURL:options:context:progress:completed:] break prefetch logic"); @synchronized (token) { [operations addPointer:(__bridge void *)operation]; From d36d5e7936fab24605e6c3bc1bf1a5079ee0fe81 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 22 Mar 2019 10:57:23 +0800 Subject: [PATCH 333/361] Revert "Move the dispatch_main_async_safe into internal macros, since it's used in implementation files but not headers" This reverts commit e702214f826813da4cc9482fa7d9698278dececa. --- SDWebImage/Private/SDInternalMacros.h | 9 --------- SDWebImage/SDWebImageCompat.h | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/SDWebImage/Private/SDInternalMacros.h b/SDWebImage/Private/SDInternalMacros.h index 9e0dee3a..edcb1ab0 100644 --- a/SDWebImage/Private/SDInternalMacros.h +++ b/SDWebImage/Private/SDInternalMacros.h @@ -9,15 +9,6 @@ #import #import "SDmetamacros.h" -#ifndef dispatch_main_async_safe -#define dispatch_main_async_safe(block)\ -if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(dispatch_get_main_queue())) {\ - block();\ -} else {\ - dispatch_async(dispatch_get_main_queue(), block);\ -} -#endif - #ifndef SD_LOCK #define SD_LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); #endif diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index 54ec168b..f47a248a 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -84,3 +84,12 @@ #ifndef NS_OPTIONS #define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type #endif + +#ifndef dispatch_main_async_safe +#define dispatch_main_async_safe(block)\ + if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(dispatch_get_main_queue())) {\ + block();\ + } else {\ + dispatch_async(dispatch_get_main_queue(), block);\ + } +#endif From 9453c2e095e1db0e70fc14526e959ac3841f0abc Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 23 Mar 2019 10:10:04 +0800 Subject: [PATCH 334/361] Remove the deprecated GCC_VERSION build settings for Demo project --- Configs/App-Shared.xcconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/Configs/App-Shared.xcconfig b/Configs/App-Shared.xcconfig index 57760e6c..d3cac8b2 100644 --- a/Configs/App-Shared.xcconfig +++ b/Configs/App-Shared.xcconfig @@ -6,8 +6,5 @@ // Name of an asset catalog app icon set whose contents will be merged into the `Info.plist`. ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon -// The compiler to use for C, C++, and Objective-C. -GCC_VERSION = - // Implicitly include the named header. The path given should either be a project relative path or an absolute path. GCC_PREFIX_HEADER = From 9fe1eee0055d19ff922289f5f8a60b93b6dfd025 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 25 Mar 2019 18:44:41 +0800 Subject: [PATCH 335/361] Rename the SDImageLoaderProtocol method naming to avoid the Selector conflict with SDWebImageManager and cause misunderstanding usage --- SDWebImage/SDImageLoader.h | 18 +++++++++--------- SDWebImage/SDImageLoadersManager.m | 10 +++++----- SDWebImage/SDWebImageDownloader.m | 4 ++-- SDWebImage/SDWebImageManager.m | 4 ++-- Tests/Tests/SDWebImageDownloaderTests.m | 4 ++-- Tests/Tests/SDWebImageTestLoader.m | 4 ++-- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/SDWebImage/SDImageLoader.h b/SDWebImage/SDImageLoader.h index e84843d0..a69f7c53 100644 --- a/SDWebImage/SDImageLoader.h +++ b/SDWebImage/SDImageLoader.h @@ -26,7 +26,7 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextLoader /** This is the built-in decoding process for image download from network or local file. - @note If you want to implement your custom loader with `loadImageWithURL:options:context:progress:completed:` API, but also want to keep compatible with SDWebImage's behavior, you'd better use this to produce image. + @note If you want to implement your custom loader with `requestImageWithURL:options:context:progress:completed:` API, but also want to keep compatible with SDWebImage's behavior, you'd better use this to produce image. @param imageData The image data from the network. Should not be nil @param imageURL The image URL from the input. Should not be nil @@ -38,7 +38,7 @@ FOUNDATION_EXPORT UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Non /** This is the built-in decoding process for image progressive download from network. It's used when `SDWebImageProgressiveLoad` option is set. (It's not required when your loader does not support progressive image loading) - @note If you want to implement your custom loader with `loadImageWithURL:options:context:progress:completed:` API, but also want to keep compatible with SDWebImage's behavior, you'd better use this to produce image. + @note If you want to implement your custom loader with `requestImageWithURL:options:context:progress:completed:` API, but also want to keep compatible with SDWebImage's behavior, you'd better use this to produce image. @param imageData The image data from the network so far. Should not be nil @param imageURL The image URL from the input. Should not be nil @@ -61,12 +61,12 @@ FOUNDATION_EXPORT UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NS /** Whether current image loader supports to load the provide image URL. - This will be checked everytime a new image request come for loader. If this return NO, we will mark this image load as failed. If return YES, we will start to call `loadImageWithURL:options:context:progress:completed:`. + This will be checked everytime a new image request come for loader. If this return NO, we will mark this image load as failed. If return YES, we will start to call `requestImageWithURL:options:context:progress:completed:`. @param url The image URL to be loaded. @return YES to continue download, NO to stop download. */ -- (BOOL)canLoadWithURL:(nullable NSURL *)url; +- (BOOL)canRequestImageForURL:(nullable NSURL *)url; /** Load the image and image data with the given URL and return the image data. You're responsible for producing the image instance. @@ -79,10 +79,10 @@ FOUNDATION_EXPORT UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NS @param completedBlock A block called when operation has been completed. @return An operation which allow the user to cancel the current request. */ -- (nullable id)loadImageWithURL:(nullable NSURL *)url - options:(SDWebImageOptions)options - context:(nullable SDWebImageContext *)context - progress:(nullable SDImageLoaderProgressBlock)progressBlock - completed:(nullable SDImageLoaderCompletedBlock)completedBlock; +- (nullable id)requestImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDImageLoaderProgressBlock)progressBlock + completed:(nullable SDImageLoaderCompletedBlock)completedBlock; @end diff --git a/SDWebImage/SDImageLoadersManager.m b/SDWebImage/SDImageLoadersManager.m index 84461fce..04607439 100644 --- a/SDWebImage/SDImageLoadersManager.m +++ b/SDWebImage/SDImageLoadersManager.m @@ -65,19 +65,19 @@ #pragma mark - SDImageLoader -- (BOOL)canLoadWithURL:(nullable NSURL *)url { +- (BOOL)canRequestImageForURL:(nullable NSURL *)url { SD_LOCK(self.loadersLock); NSArray> *loaders = self.loaders; SD_UNLOCK(self.loadersLock); for (id loader in loaders.reverseObjectEnumerator) { - if ([loader canLoadWithURL:url]) { + if ([loader canRequestImageForURL:url]) { return YES; } } return NO; } -- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDImageLoaderCompletedBlock)completedBlock { +- (id)requestImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDImageLoaderCompletedBlock)completedBlock { if (!url) { return nil; } @@ -85,8 +85,8 @@ NSArray> *loaders = self.loaders; SD_UNLOCK(self.loadersLock); for (id loader in loaders.reverseObjectEnumerator) { - if ([loader canLoadWithURL:url]) { - return [loader loadImageWithURL:url options:options context:context progress:progressBlock completed:completedBlock]; + if ([loader canRequestImageForURL:url]) { + return [loader requestImageWithURL:url options:options context:context progress:progressBlock completed:completedBlock]; } } return nil; diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 358b0d28..a044ddee 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -499,7 +499,7 @@ didReceiveResponse:(NSURLResponse *)response @implementation SDWebImageDownloader (SDImageLoader) -- (BOOL)canLoadWithURL:(NSURL *)url { +- (BOOL)canRequestImageForURL:(NSURL *)url { if (!url) { return NO; } @@ -507,7 +507,7 @@ didReceiveResponse:(NSURLResponse *)response return YES; } -- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDImageLoaderCompletedBlock)completedBlock { +- (id)requestImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDImageLoaderCompletedBlock)completedBlock { UIImage *cachedImage = context[SDWebImageContextLoaderCachedImage]; SDWebImageDownloaderOptions downloaderOptions = 0; diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 35baa08c..ca313f60 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -218,7 +218,7 @@ static id _defaultImageLoader; BOOL shouldDownload = (options & SDWebImageFromCacheOnly) == 0; shouldDownload &= (!cachedImage || options & SDWebImageRefreshCached); shouldDownload &= (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]); - shouldDownload &= [self.imageLoader canLoadWithURL:url]; + shouldDownload &= [self.imageLoader canRequestImageForURL:url]; if (shouldDownload) { if (cachedImage && options & SDWebImageRefreshCached) { // If image was found in the cache but SDWebImageRefreshCached is provided, notify about the cached image @@ -237,7 +237,7 @@ static id _defaultImageLoader; // `SDWebImageCombinedOperation` -> `SDWebImageDownloadToken` -> `downloadOperationCancelToken`, which is a `SDCallbacksDictionary` and retain the completed block below, so we need weak-strong again to avoid retain cycle @weakify(operation); - operation.loaderOperation = [self.imageLoader loadImageWithURL:url options:options context:context progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { + operation.loaderOperation = [self.imageLoader requestImageWithURL:url options:options context:context progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { @strongify(operation); if (!operation || operation.isCancelled) { // Do nothing if the operation was cancelled diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index fce1d25f..02edfaea 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -443,7 +443,7 @@ XCTestExpectation *expectation = [self expectationWithDescription:@"Custom image not works"]; SDWebImageTestLoader *loader = [[SDWebImageTestLoader alloc] init]; NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; - [loader loadImageWithURL:imageURL options:0 context:nil progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { + [loader requestImageWithURL:imageURL options:0 context:nil progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { expect(targetURL).notTo.beNil(); } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { expect(error).to.beNil(); @@ -457,7 +457,7 @@ - (void)test31ThatLoadersManagerWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Loaders manager not works"]; NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL]; - [[SDImageLoadersManager sharedManager] loadImageWithURL:imageURL options:0 context:nil progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { + [[SDImageLoadersManager sharedManager] requestImageWithURL:imageURL options:0 context:nil progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { expect(targetURL).notTo.beNil(); } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { expect(error).to.beNil(); diff --git a/Tests/Tests/SDWebImageTestLoader.m b/Tests/Tests/SDWebImageTestLoader.m index c4da8e73..32635b2d 100644 --- a/Tests/Tests/SDWebImageTestLoader.m +++ b/Tests/Tests/SDWebImageTestLoader.m @@ -16,11 +16,11 @@ @implementation SDWebImageTestLoader -- (BOOL)canLoadWithURL:(NSURL *)url { +- (BOOL)canRequestImageForURL:(NSURL *)url { return YES; } -- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDImageLoaderCompletedBlock)completedBlock { +- (id)requestImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDImageLoaderCompletedBlock)completedBlock { NSURLRequest *request = [NSURLRequest requestWithURL:url]; NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { From 0ad3dd4e5cc336a9f7f772dbe08332813f4982be Mon Sep 17 00:00:00 2001 From: Insomnia <282132315@qq.com> Date: Tue, 26 Mar 2019 00:40:26 +0800 Subject: [PATCH 336/361] Replace the weak-strong dance code with weakify && strongify depend on #2647 retry for travis failed --- SDWebImage/MapKit/MKAnnotationView+WebCache.m | 5 +++-- SDWebImage/NSButton+WebCache.m | 5 +++-- SDWebImage/UIButton+WebCache.m | 10 ++++++---- SDWebImage/UIImageView+HighlightedWebCache.m | 5 +++-- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/SDWebImage/MapKit/MKAnnotationView+WebCache.m b/SDWebImage/MapKit/MKAnnotationView+WebCache.m index a6721a9e..fed23675 100644 --- a/SDWebImage/MapKit/MKAnnotationView+WebCache.m +++ b/SDWebImage/MapKit/MKAnnotationView+WebCache.m @@ -54,13 +54,14 @@ context:(nullable SDWebImageContext *)context progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { - __weak typeof(self)weakSelf = self; + @weakify(self); [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options context:context setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { - weakSelf.image = image; + @strongify(self); + self.image = image; } progress:progressBlock completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { diff --git a/SDWebImage/NSButton+WebCache.m b/SDWebImage/NSButton+WebCache.m index 74383054..8800cea5 100644 --- a/SDWebImage/NSButton+WebCache.m +++ b/SDWebImage/NSButton+WebCache.m @@ -121,13 +121,14 @@ static NSString * const SDAlternateImageOperationKey = @"NSButtonAlternateImageO mutableContext = [NSMutableDictionary dictionary]; } mutableContext[SDWebImageContextSetImageOperationKey] = SDAlternateImageOperationKey; - __weak typeof(self)weakSelf = self; + @weakify(self); [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options context:mutableContext setImageBlock:^(NSImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { - weakSelf.alternateImage = image; + @strongify(self); + self.alternateImage = image; } progress:progressBlock completed:^(NSImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { diff --git a/SDWebImage/UIButton+WebCache.m b/SDWebImage/UIButton+WebCache.m index 54034780..e31ba9b5 100644 --- a/SDWebImage/UIButton+WebCache.m +++ b/SDWebImage/UIButton+WebCache.m @@ -104,13 +104,14 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat mutableContext = [NSMutableDictionary dictionary]; } mutableContext[SDWebImageContextSetImageOperationKey] = imageOperationKeyForState(state); - __weak typeof(self)weakSelf = self; + @weakify(self); [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options context:mutableContext setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { - [weakSelf setImage:image forState:state]; + @strongify(self); + [self setImage:image forState:state]; } progress:progressBlock completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { @@ -188,13 +189,14 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat mutableContext = [NSMutableDictionary dictionary]; } mutableContext[SDWebImageContextSetImageOperationKey] = imageOperationKeyForState(state); - __weak typeof(self)weakSelf = self; + @weakify(self); [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options context:mutableContext setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { - [weakSelf setBackgroundImage:image forState:state]; + @strongify(self); + [self setBackgroundImage:image forState:state]; } progress:progressBlock completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { diff --git a/SDWebImage/UIImageView+HighlightedWebCache.m b/SDWebImage/UIImageView+HighlightedWebCache.m index 6560f46f..c2b4dcaa 100644 --- a/SDWebImage/UIImageView+HighlightedWebCache.m +++ b/SDWebImage/UIImageView+HighlightedWebCache.m @@ -46,7 +46,7 @@ static NSString * const SDHighlightedImageOperationKey = @"UIImageViewImageOpera context:(nullable SDWebImageContext *)context progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { - __weak typeof(self)weakSelf = self; + @weakify(self); SDWebImageMutableContext *mutableContext; if (context) { mutableContext = [context mutableCopy]; @@ -59,7 +59,8 @@ static NSString * const SDHighlightedImageOperationKey = @"UIImageViewImageOpera options:options context:mutableContext setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { - weakSelf.highlightedImage = image; + @strongify(self); + self.highlightedImage = image; } progress:progressBlock completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { From b09da860b9f54c71fa8b402dadcc22d991a52bda Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 26 Mar 2019 17:36:35 +0800 Subject: [PATCH 337/361] Fix the issue cause build failure for Xcode 10.2. Fix the wrong relative path of SDWebImage.xcodeproj Fix the wrong xcconfig using ENABLE_BITCODE on debug configuration --- Configs/App-Debug.xcconfig | 3 +++ Configs/Module-Debug.xcconfig | 3 +++ Configs/Test-Debug.xcconfig | 6 ++++++ Configs/Test-Release.xcconfig | 6 ++++++ SDWebImage.xcworkspace/contents.xcworkspacedata | 2 +- Tests/SDWebImage Tests.xcodeproj/project.pbxproj | 2 -- 6 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Configs/App-Debug.xcconfig b/Configs/App-Debug.xcconfig index 2043ccce..f9ba7bef 100644 --- a/Configs/App-Debug.xcconfig +++ b/Configs/App-Debug.xcconfig @@ -6,3 +6,6 @@ // If enabled, only the active architecture is built. ONLY_ACTIVE_ARCH = YES + +// Activating this setting indicates that the target or project should generate bitcode during compilation for platforms and architectures that support it. For Archive builds, bitcode will be generated in the linked binary for submission to the App Store. For other builds, the compiler and linker will check whether the code complies with the requirements for bitcode generation, but will not generate actual bitcode. +ENABLE_BITCODE = NO diff --git a/Configs/Module-Debug.xcconfig b/Configs/Module-Debug.xcconfig index 7a80c401..c048e461 100644 --- a/Configs/Module-Debug.xcconfig +++ b/Configs/Module-Debug.xcconfig @@ -15,6 +15,9 @@ ENABLE_NS_ASSERTIONS = YES // When this setting is activated, the product will be built with options appropriate for running automated tests, such as making private interfaces accessible to the tests. ENABLE_TESTABILITY = YES +// Activating this setting indicates that the target or project should generate bitcode during compilation for platforms and architectures that support it. For Archive builds, bitcode will be generated in the linked binary for submission to the App Store. For other builds, the compiler and linker will check whether the code complies with the requirements for bitcode generation, but will not generate actual bitcode. +ENABLE_BITCODE = NO + // Specifies the degree to which the generated code is optimized for speed and binary size. GCC_OPTIMIZATION_LEVEL = 0 diff --git a/Configs/Test-Debug.xcconfig b/Configs/Test-Debug.xcconfig index d3c686e2..ab3e3059 100644 --- a/Configs/Test-Debug.xcconfig +++ b/Configs/Test-Debug.xcconfig @@ -3,3 +3,9 @@ #include "Module-Debug.xcconfig" #include "Test-Shared.xcconfig" + +// If enabled, only the active architecture is built. +ONLY_ACTIVE_ARCH = YES + +// Activating this setting indicates that the target or project should generate bitcode during compilation for platforms and architectures that support it. For Archive builds, bitcode will be generated in the linked binary for submission to the App Store. For other builds, the compiler and linker will check whether the code complies with the requirements for bitcode generation, but will not generate actual bitcode. +ENABLE_BITCODE = NO diff --git a/Configs/Test-Release.xcconfig b/Configs/Test-Release.xcconfig index b3683aed..ddd2a935 100644 --- a/Configs/Test-Release.xcconfig +++ b/Configs/Test-Release.xcconfig @@ -3,3 +3,9 @@ #include "Module-Release.xcconfig" #include "Test-Shared.xcconfig" + +// If enabled, only the active architecture is built. +ONLY_ACTIVE_ARCH = NO + +// Space-separated list of additional flags to pass to the compiler for C and Objective-C files. Be sure to backslash-escape any arguments that contain spaces or special characters, such as path names that may contain spaces. Use this setting if Xcode does not already provide UI for a particular C or Objective-C compiler flag. +OTHER_CFLAGS = -DNS_BLOCK_ASSERTIONS=1 diff --git a/SDWebImage.xcworkspace/contents.xcworkspacedata b/SDWebImage.xcworkspace/contents.xcworkspacedata index 3d719145..9e1946b2 100644 --- a/SDWebImage.xcworkspace/contents.xcworkspacedata +++ b/SDWebImage.xcworkspace/contents.xcworkspacedata @@ -2,7 +2,7 @@ + location = "group:SDWebImage.xcodeproj"> diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index e53ee549..87dca370 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -534,7 +534,6 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; - ENABLE_BITCODE = NO; INFOPLIST_FILE = "Tests Mac/Info.plist"; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; @@ -550,7 +549,6 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; - ENABLE_BITCODE = NO; INFOPLIST_FILE = "Tests Mac/Info.plist"; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; From 110b49633faefbd0777b51994780d2222d31b115 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 26 Mar 2019 18:03:14 +0800 Subject: [PATCH 338/361] Fix the warning of deprecated project localization after upgrading Xcode 10.2 --- Examples/SDWebImage Demo.xcodeproj/project.pbxproj | 2 +- SDWebImage.xcodeproj/project.pbxproj | 3 ++- Tests/SDWebImage Tests.xcodeproj/project.pbxproj | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Examples/SDWebImage Demo.xcodeproj/project.pbxproj b/Examples/SDWebImage Demo.xcodeproj/project.pbxproj index 5f85d8bd..fbad37b4 100644 --- a/Examples/SDWebImage Demo.xcodeproj/project.pbxproj +++ b/Examples/SDWebImage Demo.xcodeproj/project.pbxproj @@ -557,7 +557,7 @@ }; buildConfigurationList = 5376128F155AB74D005750A4 /* Build configuration list for PBXProject "SDWebImage Demo" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index ef29fba9..ff59b89b 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -923,10 +923,11 @@ }; buildConfigurationList = 53922D69148C55810056699D /* Build configuration list for PBXProject "SDWebImage" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 53922D64148C55810056699D; productRefGroup = 53922D70148C55820056699D /* Products */; diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 87dca370..1e3d9d5d 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -327,10 +327,11 @@ }; buildConfigurationList = DA248D491954721A00390AB0 /* Build configuration list for PBXProject "SDWebImage Tests" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = DA248D451954721A00390AB0; productRefGroup = DA248D54195472AA00390AB0 /* Products */; From c292fcccc451d193b6091bcb97d0aa6452f68ac9 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 27 Mar 2019 22:07:42 +0800 Subject: [PATCH 339/361] Remove the unused ENABLE_BITCODE xcconfig, which cause issue for watchOS platform. Even without this xcconfig, all 4 platforms build product have the correct bitcode support --- Configs/App-Debug.xcconfig | 3 --- Configs/Module-Debug.xcconfig | 3 --- Configs/Module-Shared.xcconfig | 5 ----- Configs/Test-Debug.xcconfig | 3 --- 4 files changed, 14 deletions(-) diff --git a/Configs/App-Debug.xcconfig b/Configs/App-Debug.xcconfig index f9ba7bef..2043ccce 100644 --- a/Configs/App-Debug.xcconfig +++ b/Configs/App-Debug.xcconfig @@ -6,6 +6,3 @@ // If enabled, only the active architecture is built. ONLY_ACTIVE_ARCH = YES - -// Activating this setting indicates that the target or project should generate bitcode during compilation for platforms and architectures that support it. For Archive builds, bitcode will be generated in the linked binary for submission to the App Store. For other builds, the compiler and linker will check whether the code complies with the requirements for bitcode generation, but will not generate actual bitcode. -ENABLE_BITCODE = NO diff --git a/Configs/Module-Debug.xcconfig b/Configs/Module-Debug.xcconfig index c048e461..7a80c401 100644 --- a/Configs/Module-Debug.xcconfig +++ b/Configs/Module-Debug.xcconfig @@ -15,9 +15,6 @@ ENABLE_NS_ASSERTIONS = YES // When this setting is activated, the product will be built with options appropriate for running automated tests, such as making private interfaces accessible to the tests. ENABLE_TESTABILITY = YES -// Activating this setting indicates that the target or project should generate bitcode during compilation for platforms and architectures that support it. For Archive builds, bitcode will be generated in the linked binary for submission to the App Store. For other builds, the compiler and linker will check whether the code complies with the requirements for bitcode generation, but will not generate actual bitcode. -ENABLE_BITCODE = NO - // Specifies the degree to which the generated code is optimized for speed and binary size. GCC_OPTIMIZATION_LEVEL = 0 diff --git a/Configs/Module-Shared.xcconfig b/Configs/Module-Shared.xcconfig index 71bccf54..1d6d3084 100644 --- a/Configs/Module-Shared.xcconfig +++ b/Configs/Module-Shared.xcconfig @@ -109,11 +109,6 @@ DYLIB_CURRENT_VERSION = 1 // Sets the base value for the internal `install path` (`LC_ID_DYLIB`) in a dynamic library. This will be combined with the `EXECUTABLE_PATH` to form the full install path. DYLIB_INSTALL_NAME_BASE = @rpath -// Activating this setting indicates that the target or project should generate bitcode during compilation for platforms and architectures that support it. For Archive builds, bitcode will be generated in the linked binary for submission to the App Store. For other builds, the compiler and linker will check whether the code complies with the requirements for bitcode generation, but will not generate actual bitcode. -ENABLE_BITCODE = YES -// Mac OS X does not support bitcode. -ENABLE_BITCODE[sdk=macosx*] = NO - // Controls whether `objc_msgSend` calls must be cast to the appropriate function pointer type before being called. ENABLE_STRICT_OBJC_MSGSEND = YES diff --git a/Configs/Test-Debug.xcconfig b/Configs/Test-Debug.xcconfig index ab3e3059..76e4e28c 100644 --- a/Configs/Test-Debug.xcconfig +++ b/Configs/Test-Debug.xcconfig @@ -6,6 +6,3 @@ // If enabled, only the active architecture is built. ONLY_ACTIVE_ARCH = YES - -// Activating this setting indicates that the target or project should generate bitcode during compilation for platforms and architectures that support it. For Archive builds, bitcode will be generated in the linked binary for submission to the App Store. For other builds, the compiler and linker will check whether the code complies with the requirements for bitcode generation, but will not generate actual bitcode. -ENABLE_BITCODE = NO From d85f94da9674c85db89e9b87898d2041a8840b66 Mon Sep 17 00:00:00 2001 From: Gondnat Date: Fri, 29 Mar 2019 14:16:36 +0800 Subject: [PATCH 340/361] Fix a crash, when SDAnimatedImageView dealloc, displayLinkContext in block will be a bad pointer --- SDWebImage/SDAnimatedImageView.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index 42c731d2..fc4a9988 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -742,8 +742,10 @@ static CVReturn renderCallback(CVDisplayLinkRef displayLink, const CVTimeStamp * // Calculate refresh duration NSTimeInterval duration = (double)inOutputTime->videoRefreshPeriod / ((double)inOutputTime->videoTimeScale * inOutputTime->rateScalar); // CVDisplayLink callback is not on main queue + SDAnimatedImageView *imageView = (__bridge SDAnimatedImageView *)displayLinkContext; + __weak SDAnimatedImageView *weakImageView = imageView; dispatch_async(dispatch_get_main_queue(), ^{ - [(__bridge SDAnimatedImageView *)displayLinkContext displayDidRefresh:displayLink duration:duration]; + [weakImageView displayDidRefresh:displayLink duration:duration]; }); return kCVReturnSuccess; } From cf7a5a626bb673b5f4fa4673870f3b531badf121 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 30 Mar 2019 15:47:41 +0800 Subject: [PATCH 341/361] Remove the unused intrinsicContentSize for SDAnimatedImageView. This is original from FL and it's proved to be a of FL itself, but not what UIKit/AppKit behavior. --- SDWebImage/SDAnimatedImageView.m | 19 ------------------- Tests/Tests/SDAnimatedImageTest.m | 8 ++++++++ 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index fc4a9988..b64e746c 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -228,8 +228,6 @@ static NSUInteger SDDeviceFreeMemory() { // Ensure disabled highlighting; it's not supported (see `-setHighlighted:`). super.highlighted = NO; - // UIImageView seems to bypass some accessors when calculating its intrinsic content size, so this ensures its intrinsic content size comes from the animated image. - [self invalidateIntrinsicContentSize]; // Calculate max buffer size [self calculateMaxBufferCount]; @@ -429,23 +427,6 @@ static NSUInteger SDDeviceFreeMemory() { } } -#pragma mark Auto Layout - -- (CGSize)intrinsicContentSize -{ - // Default to let UIImageView handle the sizing of its image, and anything else it might consider. - CGSize intrinsicContentSize = [super intrinsicContentSize]; - - // If we have have an animated image, use its image size. - // UIImageView's intrinsic content size seems to be the size of its image. The obvious approach, simply calling `-invalidateIntrinsicContentSize` when setting an animated image, results in UIImageView steadfastly returning `{UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric}` for its intrinsicContentSize. - // (Perhaps UIImageView bypasses its `-image` getter in its implementation of `-intrinsicContentSize`, as `-image` is not called after calling `-invalidateIntrinsicContentSize`.) - if (self.animatedImage) { - intrinsicContentSize = self.image.size; - } - - return intrinsicContentSize; -} - #pragma mark - UIImageView Method Overrides #pragma mark Image Data diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index 5af4b002..0135b4e4 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -129,6 +129,14 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun expect(image1.animatedImageFrameCount).equal(image2.animatedImageFrameCount); } +- (void)test11AnimatedImageViewIntrinsicContentSize { + // Test that SDAnimatedImageView.intrinsicContentSize return the correct value of image size + SDAnimatedImageView *imageView = [SDAnimatedImageView new]; + SDAnimatedImage *image = [SDAnimatedImage imageWithData:[self testAPNGPData]]; + imageView.image = image; + expect(imageView.intrinsicContentSize).equal(image.size); +} + - (void)test20AnimatedImageViewRendering { XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView rendering"]; SDAnimatedImageView *imageView = [[SDAnimatedImageView alloc] init]; From 8237712d36657b3e70899c3e80d812a64253f3f8 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 30 Mar 2019 18:35:55 +0800 Subject: [PATCH 342/361] Update the macOS-specify comment and explain the reason of the `imageViewLayer` method. Update macOS 10.14 behavior. --- SDWebImage/SDAnimatedImageView.m | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index b64e746c..dcd7facc 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -61,18 +61,12 @@ static NSUInteger SDDeviceFreeMemory() { #else @property (nonatomic, strong) CADisplayLink *displayLink; #endif -// Layer-backed NSImageView use a subview of `NSImageViewContainerView` to do actual layer rendering. We use this layer instead of `self.layer` during animated image rendering. -#if SD_MAC -@property (nonatomic, strong, readonly) CALayer *imageViewLayer; -#endif @end @implementation SDAnimatedImageView #if SD_UIKIT @dynamic animationRepeatCount; -#else -@dynamic imageViewLayer; #endif #pragma mark - Initializers @@ -239,7 +233,7 @@ static NSUInteger SDDeviceFreeMemory() { [self.layer setNeedsDisplay]; #if SD_MAC - [self.layer displayIfNeeded]; // macOS's imageViewLayer is not equal to self.layer. But `[super setImage:]` will impliedly mark it needsDisplay. We call `[self.layer displayIfNeeded]` to immediately refresh the imageViewLayer to avoid flashing + [self.layer displayIfNeeded]; // macOS's imageViewLayer may not equal to self.layer. But `[super setImage:]` will impliedly mark it needsDisplay. We call `[self.layer displayIfNeeded]` to immediately refresh the imageViewLayer to avoid flashing #endif } } @@ -312,13 +306,6 @@ static NSUInteger SDDeviceFreeMemory() { } #endif -#if SD_MAC -- (CALayer *)imageViewLayer { - NSView *imageView = objc_getAssociatedObject(self, NSSelectorFromString(@"_imageView")); - return imageView.layer; -} -#endif - #pragma mark - Life Cycle - (void)dealloc @@ -681,6 +668,18 @@ static NSUInteger SDDeviceFreeMemory() { } #if SD_MAC +// Layer-backed NSImageView optionally optimize to use a subview to do actual layer rendering. +// When the optimization is turned on, it calls `updateLayer` instead of `displayLayer:` to update subview's layer. +// When the optimization it turned off, this return nil and calls `displayLayer:` directly. +- (CALayer *)imageViewLayer { + NSView *imageView = imageView = objc_getAssociatedObject(self, NSSelectorFromString(@"_imageView")); + if (!imageView) { + // macOS 10.14 + imageView = objc_getAssociatedObject(self, NSSelectorFromString(@"_imageSubview")); + } + return imageView.layer; +} + - (void)updateLayer { if (_currentFrame) { From 3c28785d7644a8e6d7973c6216f219da4b00733c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 30 Mar 2019 18:55:07 +0800 Subject: [PATCH 343/361] Fix the animated image view refresh rate issue when connecting a external monitor with different refresh rate --- SDWebImage/SDAnimatedImageView.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index dcd7facc..fad2a91d 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -281,8 +281,7 @@ static NSUInteger SDDeviceFreeMemory() { - (CVDisplayLinkRef)displayLink { if (!_displayLink) { - CGDirectDisplayID displayID = CGMainDisplayID(); - CVReturn error = CVDisplayLinkCreateWithCGDisplay(displayID, &_displayLink); + CVReturn error = CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink); if (error) { return NULL; } From 505a89c029b2af5581608a413699aea591a0d496 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 31 Mar 2019 11:40:58 +0800 Subject: [PATCH 344/361] Simplify the code of `animationRepeatCount`, since there are no override logic --- SDWebImage/SDAnimatedImageView.m | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index fad2a91d..e898362b 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -66,7 +66,7 @@ static NSUInteger SDDeviceFreeMemory() { @implementation SDAnimatedImageView #if SD_UIKIT -@dynamic animationRepeatCount; +@dynamic animationRepeatCount; // we re-use this property from `UIImageView` super class on iOS. #endif #pragma mark - Initializers @@ -238,15 +238,6 @@ static NSUInteger SDDeviceFreeMemory() { } } -- (void)setAnimationRepeatCount:(NSInteger)animationRepeatCount -{ -#if SD_MAC - _animationRepeatCount = animationRepeatCount; -#else - [super setAnimationRepeatCount:animationRepeatCount]; -#endif -} - #if SD_UIKIT - (void)setRunLoopMode:(NSString *)runLoopMode { From f9e80d18eb49cde78d336ff794cd0e7c104bb065 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 31 Mar 2019 15:36:04 +0800 Subject: [PATCH 345/361] Fix the current caches manager, does not apply the SDImageCache.sharedImageCache. Fix the thread safe issue of caches manager. Update the test cases and documents about this behavior. --- SDWebImage/SDImageCachesManager.h | 2 +- SDWebImage/SDImageCachesManager.m | 14 ++++++++++++++ SDWebImage/SDImageLoadersManager.h | 3 +++ Tests/Tests/SDImageCacheTests.m | 17 +++-------------- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/SDWebImage/SDImageCachesManager.h b/SDWebImage/SDImageCachesManager.h index 08eece9a..41e5b046 100644 --- a/SDWebImage/SDImageCachesManager.h +++ b/SDWebImage/SDImageCachesManager.h @@ -19,7 +19,7 @@ typedef NS_ENUM(NSUInteger, SDImageCachesManagerOperationPolicy) { @interface SDImageCachesManager : NSObject /** - Returns the global shared caches manager instance. + Returns the global shared caches manager instance. By default we will set [`SDImageCache.sharedImageCache`] into the caches array. */ @property (nonatomic, class, readonly, nonnull) SDImageCachesManager *sharedManager; diff --git a/SDWebImage/SDImageCachesManager.m b/SDWebImage/SDImageCachesManager.m index fd31cd9f..b02f3f55 100644 --- a/SDWebImage/SDImageCachesManager.m +++ b/SDWebImage/SDImageCachesManager.m @@ -8,6 +8,13 @@ #import "SDImageCachesManager.h" #import "SDImageCachesManagerOperation.h" +#import "SDImageCache.h" + +@interface SDImageCachesManager () + +@property (nonatomic, strong, nonnull) dispatch_semaphore_t cachesLock; + +@end @implementation SDImageCachesManager @@ -28,6 +35,9 @@ self.removeOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; self.containsOperationPolicy = SDImageCachesManagerOperationPolicySerial; self.clearOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; + // initialize with default image caches + self.caches = @[[SDImageCache sharedImageCache]]; + self.cachesLock = dispatch_semaphore_create(1); } return self; } @@ -38,21 +48,25 @@ if (![cache conformsToProtocol:@protocol(SDImageCache)]) { return; } + SD_LOCK(self.cachesLock); NSMutableArray> *mutableCaches = [self.caches mutableCopy]; if (!mutableCaches) { mutableCaches = [NSMutableArray array]; } [mutableCaches addObject:cache]; self.caches = [mutableCaches copy]; + SD_UNLOCK(self.cachesLock); } - (void)removeCache:(id)cache { if (![cache conformsToProtocol:@protocol(SDImageCache)]) { return; } + SD_LOCK(self.cachesLock); NSMutableArray> *mutableCaches = [self.caches mutableCopy]; [mutableCaches removeObject:cache]; self.caches = [mutableCaches copy]; + SD_UNLOCK(self.cachesLock); } #pragma mark - SDImageCache diff --git a/SDWebImage/SDImageLoadersManager.h b/SDWebImage/SDImageLoadersManager.h index 1e278628..651b5e9e 100644 --- a/SDWebImage/SDImageLoadersManager.h +++ b/SDWebImage/SDImageLoadersManager.h @@ -10,6 +10,9 @@ @interface SDImageLoadersManager : NSObject +/** + Returns the global shared loaders manager instance. By default we will set [`SDWebImageDownloader.sharedDownloader`] into the loaders array. + */ @property (nonatomic, class, readonly, nonnull) SDImageLoadersManager *sharedManager; /** diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index 6e4e08ff..af110c18 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -27,14 +27,6 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; @implementation SDImageCacheTests -+ (void)setUp { - [[SDImageCachesManager sharedManager] addCache:[SDImageCache sharedImageCache]]; -} - -+ (void)tearDown { - [[SDImageCachesManager sharedManager] removeCache:[SDImageCache sharedImageCache]]; -} - - (void)test01SharedImageCache { expect([SDImageCache sharedImageCache]).toNot.beNil(); } @@ -452,8 +444,7 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; SDImageCachesManager *cachesManager = [[SDImageCachesManager alloc] init]; SDImageCache *cache1 = [[SDImageCache alloc] initWithNamespace:@"cache1"]; SDImageCache *cache2 = [[SDImageCache alloc] initWithNamespace:@"cache2"]; - [cachesManager addCache:cache1]; - [cachesManager addCache:cache2]; + cachesManager.caches = @[cache1, cache2]; [[NSFileManager defaultManager] removeItemAtPath:cache1.diskCachePath error:nil]; [[NSFileManager defaultManager] removeItemAtPath:cache2.diskCachePath error:nil]; @@ -502,8 +493,7 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; SDImageCachesManager *cachesManager = [[SDImageCachesManager alloc] init]; SDImageCache *cache1 = [[SDImageCache alloc] initWithNamespace:@"cache1"]; SDImageCache *cache2 = [[SDImageCache alloc] initWithNamespace:@"cache2"]; - [cachesManager addCache:cache1]; - [cachesManager addCache:cache2]; + cachesManager.caches = @[cache1, cache2]; [[NSFileManager defaultManager] removeItemAtPath:cache1.diskCachePath error:nil]; [[NSFileManager defaultManager] removeItemAtPath:cache2.diskCachePath error:nil]; @@ -543,8 +533,7 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; SDImageCachesManager *cachesManager = [[SDImageCachesManager alloc] init]; SDImageCache *cache1 = [[SDImageCache alloc] initWithNamespace:@"cache1"]; SDImageCache *cache2 = [[SDImageCache alloc] initWithNamespace:@"cache2"]; - [cachesManager addCache:cache1]; - [cachesManager addCache:cache2]; + cachesManager.caches = @[cache1, cache2]; [[NSFileManager defaultManager] removeItemAtPath:cache1.diskCachePath error:nil]; [[NSFileManager defaultManager] removeItemAtPath:cache2.diskCachePath error:nil]; From f060310ffe6a3dcc99237eb3aed18e9b59f1fd5f Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 31 Mar 2019 15:53:33 +0800 Subject: [PATCH 346/361] Remove the previous using atomic property, use lock instead. --- SDWebImage/SDImageCachesManager.h | 2 +- SDWebImage/SDImageCachesManager.m | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/SDWebImage/SDImageCachesManager.h b/SDWebImage/SDImageCachesManager.h index 41e5b046..2c0d7b03 100644 --- a/SDWebImage/SDImageCachesManager.h +++ b/SDWebImage/SDImageCachesManager.h @@ -58,7 +58,7 @@ typedef NS_ENUM(NSUInteger, SDImageCachesManagerOperationPolicy) { /** All caches in caches manager. The caches array is a priority queue, which means the later added cache will have the highest priority */ -@property (atomic, copy, readwrite, nullable) NSArray> *caches; +@property (nonatomic, copy, readwrite, nullable) NSArray> *caches; /** Add a new cache to the end of caches array. Which has the highest priority. diff --git a/SDWebImage/SDImageCachesManager.m b/SDWebImage/SDImageCachesManager.m index b02f3f55..1ef33e85 100644 --- a/SDWebImage/SDImageCachesManager.m +++ b/SDWebImage/SDImageCachesManager.m @@ -75,7 +75,9 @@ if (!key) { return nil; } - NSArray> *caches = [self.caches copy]; + SD_LOCK(self.cachesLock); + NSArray> *caches = self.caches; + SD_UNLOCK(self.cachesLock); NSUInteger count = caches.count; if (count == 0) { return nil; @@ -117,7 +119,9 @@ if (!key) { return; } - NSArray> *caches = [self.caches copy]; + SD_LOCK(self.cachesLock); + NSArray> *caches = self.caches; + SD_UNLOCK(self.cachesLock); NSUInteger count = caches.count; if (count == 0) { return; @@ -155,7 +159,9 @@ if (!key) { return; } - NSArray> *caches = [self.caches copy]; + SD_LOCK(self.cachesLock); + NSArray> *caches = self.caches; + SD_UNLOCK(self.cachesLock); NSUInteger count = caches.count; if (count == 0) { return; @@ -193,7 +199,9 @@ if (!key) { return; } - NSArray> *caches = [self.caches copy]; + SD_LOCK(self.cachesLock); + NSArray> *caches = self.caches; + SD_UNLOCK(self.cachesLock); NSUInteger count = caches.count; if (count == 0) { return; @@ -230,7 +238,9 @@ } - (void)clearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock { - NSArray> *caches = [self.caches copy]; + SD_LOCK(self.cachesLock); + NSArray> *caches = self.caches; + SD_UNLOCK(self.cachesLock); NSUInteger count = caches.count; if (count == 0) { return; From 36e89af004efea931c3320fb8c5239af049cfcad Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 31 Mar 2019 17:06:29 +0800 Subject: [PATCH 347/361] Update the final 5.0.0 API diff and 5.0 migration guideline --- Docs/API-Diff/5.0/apidiff.html | 11 +++-------- Docs/SDWebImage-5.0-Migration-guide.md | 27 +++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Docs/API-Diff/5.0/apidiff.html b/Docs/API-Diff/5.0/apidiff.html index 0dbd1fd0..e1820677 100644 --- a/Docs/API-Diff/5.0/apidiff.html +++ b/Docs/API-Diff/5.0/apidiff.html @@ -515,8 +515,8 @@
Added SDImageLoaderDecodeImageData()
Added SDImageLoaderDecodeProgressiveImageData()
Added SDImageLoader
-
Added -[SDImageLoader canLoadWithURL:]
-
Added -[SDImageLoader loadImageWithURL:options:context:progress:completed:]
+
Added -[SDImageLoader canRequestImageForURL:]
+
Added -[SDImageLoader requestImageWithURL:options:context:progress:completed:]
@@ -686,12 +686,6 @@
Removed #def dispatch_queue_async_safe
- -
-
Added #def SD_LOCK
-
Added #def SD_UNLOCK
-
-
@@ -770,6 +764,7 @@
Added SDWebImageDownloader.config
Added SDWebImageDownloader.requestModifier
Added -[SDWebImageDownloader initWithConfig:]
+
Added -[SDWebImageDownloader downloadImageWithURL:completed:]
Added -[SDWebImageDownloader downloadImageWithURL:options:context:progress:completed:]
diff --git a/Docs/SDWebImage-5.0-Migration-guide.md b/Docs/SDWebImage-5.0-Migration-guide.md index c9d07cdf..b71060b7 100644 --- a/Docs/SDWebImage-5.0-Migration-guide.md +++ b/Docs/SDWebImage-5.0-Migration-guide.md @@ -58,16 +58,31 @@ In order to clean up things and make our core project do less things, we decided By taking the advantage of the [Custom Loader](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-loader-50) feature, we introduced a plugin to allow easy loading images from the Photos Library. See [SDWebImagePhotosPlugin](https://github.com/SDWebImage/SDWebImagePhotosPlugin) for more detailed information. -### Notable Behavior Changes +### Notable Behavior Changes (without API breaking) #### Cache +##### Cache Paths + `SDImageCache` in 5.x, use `~/Library/Caches/com.hackemist.SDImageCache/default/` as default cache path. However, 4.x use `~/Library/Caches/default/com.hackemist.SDWebImageCache.default/`. And don't be worried, we will do the migration automatically once the shared cache initialized. However, if you have some other custom namespace cache instance, you should try to do migration by yourself. But typically, since the cache is designed to be invalid at any time, you'd better not to bind some important logic related on that cache path changes. And, if you're previously using any version from `5.0.0-beta` to `5.0.0-beta3`, please note that the cache folder has been temporarily moved to `~/Library/Caches/default/com.hackemist.SDImageCache.default/`, however, the final release version of 5.0.0 use the path above. If you upgrade from those beta version, you may need manually do migration, check `+[SDDiskCache moveCacheDirectoryFromPath:toPath:]` for detail information. +##### Cache Cost Function + +`SDImageCacheConfig.maxMemoryCost` can be used to specify the memory cost limit. In the 4.x, the cost function is the **pixel count** of images. However, 5.x change it into the total **bytes size** of images. + +Because for memory cache, we actually care about the memory usage about bytes, but not the count of pixels. And pixel count can not accurately represent the memory usage. + +The bytes of a image occupied in the memory, can use the simple formula below: + +**bytes size** = **pixel count** \* **bytes per pixel** + +The **bytes per pixel** is a constant depends on [image pixel format](https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_images/dq_images.html). For mostly used images (8 bits per channel with alpha), the value is 4. So you can simply migrate your previous pixel count value with 4 multiplied. + + #### Prefetcher `SDWebImagePrefetcher` in 5.x, change the concept of fetching batch of URLs. Now, each time you call `prefetchURLs:`, you will get a token which represents the specified URLs list. It does not cancel the previous URLs which is prefetching, which make the shared prefetcher behaves more intuitively. @@ -105,10 +120,14 @@ prefetcher.prefetchURLs([url1, url2]) - `SDCacheQueryCompletedBlock` renamed to `SDImageCacheQueryCompletionBlock` - `SDWebImageCheckCacheCompletionBlock` renamed to `SDImageCacheCheckCompletionBlock` - `SDWebImageCalculateSizeBlock` renamed to `SDImageCacheCalculateSizeBlock` +- `getSize` renamed to `totalDiskSize` +- `getDiskCount` renamed to `totalDiskCount` #### SDImageCacheConfig - `shouldDecompressImages` removed. Use `SDImageCacheAvoidDecodeImage` in cache options instead +- `maxCacheAge` renamed to `maxDiskAge` +- `maxCacheSize` renamed to `maxDiskSize` #### SDWebImageManager @@ -183,7 +202,7 @@ prefetcher.prefetchURLs([url1, url2]) - `prefetchURLs:` and `prefetchURLs:progress:completed:` return types changed from `void` to `SDWebImagePrefetchToken` - `prefetcherQueue` property renamed to `delegateQueue` -- `maxConcurrentDownloads` property removed, use `SDWebImageManager.downloader` config instead +- `maxConcurrentDownloads` replaced with `maxConcurrentPrefetchCount` #### SDImageCoder - `SDCGColorSpaceGetDeviceRGB()` moved to `+[SDImageCoderHelper colorSpaceGetDeviceRGB]` @@ -250,5 +269,7 @@ In SDWebImage 5.0 we did a clean up of the API. We are using many modern Objecti - `sd_currentAlternateImageURL()` changed to `sd_currentAlternateImageURL` ### Full API Diff -For advanced user who need the detailed API diff, we provide the full diff in a HTML web page: [SDWebImage 5.0 API Diff](https://htmlpreview.github.io/?https://github.com/rs/SDWebImage/blob/5.x/Docs/API-Diff/5.0/apidiff.html) +For advanced user who need the detailed API diff, we provide the full diff in a HTML web page (Currently based on 4.4.4 and 5.0.0-beta4): + +[SDWebImage 5.0 API Diff](https://htmlpreview.github.io/?https://github.com/rs/SDWebImage/blob/master/Docs/API-Diff/5.0/apidiff.html). From 75d3adedfa99fa3179470b72f3863163f6d1dd78 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 31 Mar 2019 18:09:17 +0800 Subject: [PATCH 348/361] Update the coders manager initializer, without the useless mutable copy Update the comments --- SDWebImage/SDImageCachesManager.m | 4 ++-- SDWebImage/SDImageCodersManager.h | 6 +++--- SDWebImage/SDImageCodersManager.m | 3 +-- SDWebImage/SDImageLoadersManager.m | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/SDWebImage/SDImageCachesManager.m b/SDWebImage/SDImageCachesManager.m index 1ef33e85..52694704 100644 --- a/SDWebImage/SDImageCachesManager.m +++ b/SDWebImage/SDImageCachesManager.m @@ -36,8 +36,8 @@ self.containsOperationPolicy = SDImageCachesManagerOperationPolicySerial; self.clearOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; // initialize with default image caches - self.caches = @[[SDImageCache sharedImageCache]]; - self.cachesLock = dispatch_semaphore_create(1); + _caches = @[[SDImageCache sharedImageCache]]; + _cachesLock = dispatch_semaphore_create(1); } return self; } diff --git a/SDWebImage/SDImageCodersManager.h b/SDWebImage/SDImageCodersManager.h index e4276464..cd77091a 100644 --- a/SDWebImage/SDImageCodersManager.h +++ b/SDWebImage/SDImageCodersManager.h @@ -17,10 +17,10 @@ Note: the `coders` getter will return the coders in their reversed order Example: - - by default we internally set coders = `IOCoder`, `GIFCoder` - - calling `coders` will return `@[IOCoder, GIFCoder]` + - by default we internally set coders = `IOCoder`, `GIFCoder`, `APNGCoder` + - calling `coders` will return `@[IOCoder, GIFCoder, APNGCoder]` - call `[addCoder:[MyCrazyCoder new]]` - - calling `coders` now returns `@[IOCoder, GIFCoder, MyCrazyCoder]` + - calling `coders` now returns `@[IOCoder, GIFCoder, APNGCoder, MyCrazyCoder]` Coders ------ diff --git a/SDWebImage/SDImageCodersManager.m b/SDWebImage/SDImageCodersManager.m index 77522cd4..e358542b 100644 --- a/SDWebImage/SDImageCodersManager.m +++ b/SDWebImage/SDImageCodersManager.m @@ -31,8 +31,7 @@ - (instancetype)init { if (self = [super init]) { // initialize with default coders - NSMutableArray> *mutableCoders = [@[[SDImageIOCoder sharedCoder], [SDImageGIFCoder sharedCoder], [SDImageAPNGCoder sharedCoder]] mutableCopy]; - _coders = [mutableCoders copy]; + _coders = @[[SDImageIOCoder sharedCoder], [SDImageGIFCoder sharedCoder], [SDImageAPNGCoder sharedCoder]]; _codersLock = dispatch_semaphore_create(1); } return self; diff --git a/SDWebImage/SDImageLoadersManager.m b/SDWebImage/SDImageLoadersManager.m index 04607439..ecb476c5 100644 --- a/SDWebImage/SDImageLoadersManager.m +++ b/SDWebImage/SDImageLoadersManager.m @@ -30,8 +30,8 @@ self = [super init]; if (self) { // initialize with default image loaders - self.loaders = @[[SDWebImageDownloader sharedDownloader]]; - self.loadersLock = dispatch_semaphore_create(1); + _loaders = @[[SDWebImageDownloader sharedDownloader]]; + _loadersLock = dispatch_semaphore_create(1); } return self; } From 78071effe62d93a405c9de58d4f4cadac62aa014 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 31 Mar 2019 20:14:27 +0800 Subject: [PATCH 349/361] Update the changelog and readme to point to the master branch instead of 5.x Ready for merge back --- CHANGELOG.md | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++- README.md | 20 ++++++++-------- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd88a92c..d77da0c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,68 @@ +## [5.0.0 Major release - Customizable SDWebImage, on Mar 31th, 2019](https://github.com/rs/SDWebImage/releases/tag/5.0.0) +See [all tickets marked for the 5.0.0 release](https://github.com/SDWebImage/SDWebImage/milestone/15) + +### Features + +#### Animated Image +- Introduce `SDAnimatedImageView` and `SDAnimatedImage` for full stack solution of animated images. +- Supports custom coders for nearly every animated image format. +- Supports progressive loading for animated images. +- iOS/tvOS/macOS cross-platform support. + +#### Transformer +- Using transformer to apply image processing after image was loaded. +- Built-in transformer for common usage: Rounded Corner, Resize, Crop, Flip, Rotate, Tint Color, Blur Effect, Core Image Filter... +- Convenient category methods for `UIImage`/`NSImage` + +#### Custom Loader +- Using loader protocol to implements your own image loader. +- Not limited on HTTP, you can even using SDWebImage with PhotoKit and third-party SDKs. +- Supports multiple loaders at the same time using `SDImageLoadersManager`. + +#### Custom Cache +- Using cache protocol to implements your own image cache. +- Standalone disk cache and memory cache class for advanced usage and customization. +- Supports multiple caches at the same time using `SDImageCachesManager`. + +#### Indicator +- Use indicator to provide a loading view, customizable +- Built-in Activity Indicator and Progress Indicator. +- iOS/tvOS/macOS cross-platform support. + +#### Plugins +- All external image format coders are plugins. Supports WebP, HEIF, BPG, FLIF, SVG, PDF... Choose what you need in: [Coder Plugin List](https://github.com/SDWebImage/SDWebImage/wiki/Coder-Plugin-List) +- PhotoKit loader as a plugin: [SDWebImagePhotosPlugin](https://github.com/SDWebImage/SDWebImagePhotosPlugin) +- FLAnimatedImage integration as a plugin: [SDWebImageFLPlugin](https://github.com/SDWebImage/SDWebImageFLPlugin) +- YYImage/YYCache integration as a plugin: [SDWebImageYYPlugin](https://github.com/SDWebImage/SDWebImageYYPlugin) + +### Improvements + +#### Swift +- Better Swift support with some manual renaming APIs. +- Full nullability annotation. +- Using class property for shared instance. +- Using `NS_TYPED_ENUM` and `NS_STRING_ENUM` for better generated APIs. + +#### API +- Using context option to control detail behavior for each image request beyond the limit of enums. +- Using prefetcher to manage token (list of URL requests) to avoid conflict. +- Use request modifier to modify constructed URLRequest. + +### Project + +- Supports the latest Xcode 10. +- Supports iOS 8.0+/tvOS 9.0+/watchOS 2.0+/macOS 10.10+. + +### Migration + +Check [5.0 migration guide](https://github.com/SDWebImage/SDWebImage/wiki/5.0-Migration-guide) for the migration from 4.x to 5.x. + +## [4.0.0 - New platforms (Mac OS X and watchOS) + refactoring, on Jan 28th, 2017](https://github.com/SDWebImage/SDWebImage/releases/tag/4.0.0) + +See [all tickets marked for the 4.0.0 release](https://github.com/SDWebImage/SDWebImage/milestone/3) +Versions 4.0.0-beta and 4.0.0-beta 2 list all the changes. + + ## [5.0.0-beta6 - 5.0 Beta, on Mar 15th, 2019](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta6) See [all tickets marked for the 5.0.0-beta6 release](https://github.com/rs/SDWebImage/milestone/30) @@ -180,7 +245,7 @@ See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/ #### Backwards incompatible changes -See the [5.0 Migration Guide](https://raw.githubusercontent.com/rs/SDWebImage/5.x/Docs/SDWebImage-5.0-Migration-guide.md) for a list of comprehensive changes and the way to update your code +See the [5.0 Migration Guide](https://raw.githubusercontent.com/rs/SDWebImage/master/Docs/SDWebImage-5.0-Migration-guide.md) for a list of comprehensive changes and the way to update your code #### Features - Introduce `SDAnimatedImageView`, `SDAnimatedImage` and refactor the way we handle animated images #2140 diff --git a/README.md b/README.md index b06c0ea8..f245dbaa 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- +

@@ -87,7 +87,7 @@ You can check the latest [5.x branch](https://github.com/SDWebImage/SDWebImage/t - Read the [Documentation @ CocoaDocs](http://cocoadocs.org/docsets/SDWebImage/) - Try the example by downloading the project from Github or even easier using CocoaPods try `pod try SDWebImage` - Read the [Installation Guide](https://github.com/SDWebImage/SDWebImage/wiki/Installation-Guide) -- Read the [SDWebImage 5.0 Migration Guide](https://raw.githubusercontent.com/SDWebImage/SDWebImage/5.x/Docs/SDWebImage-5.0-Migration-guide.md) to get an idea of the changes from 4.x to 5.x +- Read the [SDWebImage 5.0 Migration Guide](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/SDWebImage-5.0-Migration-guide.md) to get an idea of the changes from 4.x to 5.x - Read the [SDWebImage 4.0 Migration Guide](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/SDWebImage-4.0-Migration-guide.md) to get an idea of the changes from 3.x to 4.x - Read the [Common Problems](https://github.com/SDWebImage/SDWebImage/wiki/Common-Problems) to find the solution for common problems - Go to the [Wiki Page](https://github.com/SDWebImage/SDWebImage/wiki) for more information such as [Advanced Usage](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage) @@ -229,26 +229,26 @@ All source code is licensed under the [MIT License](https://raw.github.com/SDWeb #### High Level Diagram

- +

#### Overall Class Diagram

- +

#### Top Level API Diagram

- +

#### Main Sequence Diagram

- +

#### More detailed diagrams -- [Manager API Diagram](https://raw.githubusercontent.com/SDWebImage/SDWebImage/5.x/Docs/Diagrams/SDWebImageManagerClassDiagram.png) -- [Coders API Diagram](https://raw.githubusercontent.com/SDWebImage/SDWebImage/5.x/Docs/Diagrams/SDWebImageCodersClassDiagram.png) -- [Loader API Diagram](https://raw.githubusercontent.com/SDWebImage/SDWebImage/5.x/Docs/Diagrams/SDWebImageLoaderClassDiagram.png) -- [Cache API Diagram](https://raw.githubusercontent.com/SDWebImage/SDWebImage/5.x/Docs/Diagrams/SDWebImageCacheClassDiagram.png) +- [Manager API Diagram](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/Diagrams/SDWebImageManagerClassDiagram.png) +- [Coders API Diagram](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/Diagrams/SDWebImageCodersClassDiagram.png) +- [Loader API Diagram](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/Diagrams/SDWebImageLoaderClassDiagram.png) +- [Cache API Diagram](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/Diagrams/SDWebImageCacheClassDiagram.png) From 9f262fc8cf97f5f95ec56c6195b7b037685af88d Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 31 Mar 2019 21:26:55 +0800 Subject: [PATCH 350/361] Fix that `SDWebImageDownloadStartNotification` declare twice in header files. One is in downloader, another is in download operation --- SDWebImage/SDWebImageDownloader.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index f1bcc8e9..07433919 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -85,9 +85,6 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { SDWebImageDownloaderPreloadAllFrames = 1 << 11 }; -FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStartNotification; -FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStopNotification; - typedef SDImageLoaderProgressBlock SDWebImageDownloaderProgressBlock; typedef SDImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock; From 9d4b53118e0e06c058e6bd214ff2605eb9787f6c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 31 Mar 2019 23:07:20 +0800 Subject: [PATCH 351/361] Move the declare and the define into the downloader, make the import success. Update to NSNotificationName --- SDWebImage/SDWebImageDownloader.h | 5 +++++ SDWebImage/SDWebImageDownloader.m | 5 +++++ SDWebImage/SDWebImageDownloaderOperation.h | 7 ------- SDWebImage/SDWebImageDownloaderOperation.m | 5 ----- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 07433919..f4e3830f 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -85,6 +85,11 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { SDWebImageDownloaderPreloadAllFrames = 1 << 11 }; +FOUNDATION_EXPORT NSNotificationName _Nonnull const SDWebImageDownloadStartNotification; +FOUNDATION_EXPORT NSNotificationName _Nonnull const SDWebImageDownloadReceiveResponseNotification; +FOUNDATION_EXPORT NSNotificationName _Nonnull const SDWebImageDownloadStopNotification; +FOUNDATION_EXPORT NSNotificationName _Nonnull const SDWebImageDownloadFinishNotification; + typedef SDImageLoaderProgressBlock SDWebImageDownloaderProgressBlock; typedef SDImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock; diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 155a16e5..6ae608f9 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -11,6 +11,11 @@ #import "SDWebImageDownloaderOperation.h" #import "SDWebImageError.h" +NSNotificationName const SDWebImageDownloadStartNotification = @"SDWebImageDownloadStartNotification"; +NSNotificationName const SDWebImageDownloadReceiveResponseNotification = @"SDWebImageDownloadReceiveResponseNotification"; +NSNotificationName const SDWebImageDownloadStopNotification = @"SDWebImageDownloadStopNotification"; +NSNotificationName const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinishNotification"; + static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; @interface SDWebImageDownloadToken () diff --git a/SDWebImage/SDWebImageDownloaderOperation.h b/SDWebImage/SDWebImageDownloaderOperation.h index 01b7ea6d..b660771f 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.h +++ b/SDWebImage/SDWebImageDownloaderOperation.h @@ -10,13 +10,6 @@ #import "SDWebImageDownloader.h" #import "SDWebImageOperation.h" -FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStartNotification; -FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadReceiveResponseNotification; -FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStopNotification; -FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification; - - - /** Describes a downloader operation. If one wants to use a custom downloader op, it needs to inherit from `NSOperation` and conform to this protocol For the description about these methods, see `SDWebImageDownloaderOperation` diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 39aad9cd..c3dc3693 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -16,11 +16,6 @@ const float NSURLSessionTaskPriorityDefault = 0.5; const float NSURLSessionTaskPriorityLow = 0.25; #endif -NSString *const SDWebImageDownloadStartNotification = @"SDWebImageDownloadStartNotification"; -NSString *const SDWebImageDownloadReceiveResponseNotification = @"SDWebImageDownloadReceiveResponseNotification"; -NSString *const SDWebImageDownloadStopNotification = @"SDWebImageDownloadStopNotification"; -NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinishNotification"; - static NSString *const kProgressCallbackKey = @"progress"; static NSString *const kCompletedCallbackKey = @"completed"; From aa890c5d9a8966db320396c64037687530b6cae1 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Mon, 1 Apr 2019 16:00:13 +0800 Subject: [PATCH 352/361] Guarantee caches of CachesManager thread-safe --- SDWebImage/SDImageCachesManager.h | 2 +- SDWebImage/SDImageCachesManager.m | 42 ++++++++++++++++--------------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/SDWebImage/SDImageCachesManager.h b/SDWebImage/SDImageCachesManager.h index 2c0d7b03..db6a9a43 100644 --- a/SDWebImage/SDImageCachesManager.h +++ b/SDWebImage/SDImageCachesManager.h @@ -58,7 +58,7 @@ typedef NS_ENUM(NSUInteger, SDImageCachesManagerOperationPolicy) { /** All caches in caches manager. The caches array is a priority queue, which means the later added cache will have the highest priority */ -@property (nonatomic, copy, readwrite, nullable) NSArray> *caches; +@property (nonatomic, copy, nullable) NSArray> *caches; /** Add a new cache to the end of caches array. Which has the highest priority. diff --git a/SDWebImage/SDImageCachesManager.m b/SDWebImage/SDImageCachesManager.m index 52694704..18657853 100644 --- a/SDWebImage/SDImageCachesManager.m +++ b/SDWebImage/SDImageCachesManager.m @@ -17,6 +17,9 @@ @end @implementation SDImageCachesManager +{ + NSMutableArray> *caches_; +} + (SDImageCachesManager *)sharedManager { static dispatch_once_t onceToken; @@ -36,12 +39,28 @@ self.containsOperationPolicy = SDImageCachesManagerOperationPolicySerial; self.clearOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; // initialize with default image caches - _caches = @[[SDImageCache sharedImageCache]]; + caches_ = [NSMutableArray arrayWithObject:[SDImageCache sharedImageCache]]; _cachesLock = dispatch_semaphore_create(1); } return self; } +- (NSArray> *)caches { + SD_LOCK(self.cachesLock); + NSArray> *caches = [caches_ copy]; + SD_UNLOCK(self.cachesLock); + return caches; +} + +- (void)setCaches:(NSArray> *)caches { + SD_LOCK(self.cachesLock); + [caches_ removeAllObjects]; + if (caches.count) { + [caches_ addObjectsFromArray:caches]; + } + SD_UNLOCK(self.cachesLock); +} + #pragma mark - Cache IO operations - (void)addCache:(id)cache { @@ -49,12 +68,7 @@ return; } SD_LOCK(self.cachesLock); - NSMutableArray> *mutableCaches = [self.caches mutableCopy]; - if (!mutableCaches) { - mutableCaches = [NSMutableArray array]; - } - [mutableCaches addObject:cache]; - self.caches = [mutableCaches copy]; + [caches_ addObject:cache]; SD_UNLOCK(self.cachesLock); } @@ -63,9 +77,7 @@ return; } SD_LOCK(self.cachesLock); - NSMutableArray> *mutableCaches = [self.caches mutableCopy]; - [mutableCaches removeObject:cache]; - self.caches = [mutableCaches copy]; + [caches_ removeObject:cache]; SD_UNLOCK(self.cachesLock); } @@ -75,9 +87,7 @@ if (!key) { return nil; } - SD_LOCK(self.cachesLock); NSArray> *caches = self.caches; - SD_UNLOCK(self.cachesLock); NSUInteger count = caches.count; if (count == 0) { return nil; @@ -119,9 +129,7 @@ if (!key) { return; } - SD_LOCK(self.cachesLock); NSArray> *caches = self.caches; - SD_UNLOCK(self.cachesLock); NSUInteger count = caches.count; if (count == 0) { return; @@ -159,9 +167,7 @@ if (!key) { return; } - SD_LOCK(self.cachesLock); NSArray> *caches = self.caches; - SD_UNLOCK(self.cachesLock); NSUInteger count = caches.count; if (count == 0) { return; @@ -199,9 +205,7 @@ if (!key) { return; } - SD_LOCK(self.cachesLock); NSArray> *caches = self.caches; - SD_UNLOCK(self.cachesLock); NSUInteger count = caches.count; if (count == 0) { return; @@ -238,9 +242,7 @@ } - (void)clearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock { - SD_LOCK(self.cachesLock); NSArray> *caches = self.caches; - SD_UNLOCK(self.cachesLock); NSUInteger count = caches.count; if (count == 0) { return; From 60255f5bd2b25b6036711d5fb8965316c6fd4b6f Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Mon, 1 Apr 2019 17:19:11 +0800 Subject: [PATCH 353/361] Thread-safe for CodersManager and LoadersManager --- SDWebImage/SDImageCachesManager.m | 14 +++++----- SDWebImage/SDImageCodersManager.h | 2 +- SDWebImage/SDImageCodersManager.m | 42 +++++++++++++++++------------- SDWebImage/SDImageLoadersManager.h | 2 +- SDWebImage/SDImageLoadersManager.m | 36 +++++++++++++++---------- 5 files changed, 55 insertions(+), 41 deletions(-) diff --git a/SDWebImage/SDImageCachesManager.m b/SDWebImage/SDImageCachesManager.m index 18657853..e8d8d319 100644 --- a/SDWebImage/SDImageCachesManager.m +++ b/SDWebImage/SDImageCachesManager.m @@ -18,7 +18,7 @@ @implementation SDImageCachesManager { - NSMutableArray> *caches_; + NSMutableArray> *_imageCaches; } + (SDImageCachesManager *)sharedManager { @@ -39,7 +39,7 @@ self.containsOperationPolicy = SDImageCachesManagerOperationPolicySerial; self.clearOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; // initialize with default image caches - caches_ = [NSMutableArray arrayWithObject:[SDImageCache sharedImageCache]]; + _imageCaches = [NSMutableArray arrayWithObject:[SDImageCache sharedImageCache]]; _cachesLock = dispatch_semaphore_create(1); } return self; @@ -47,16 +47,16 @@ - (NSArray> *)caches { SD_LOCK(self.cachesLock); - NSArray> *caches = [caches_ copy]; + NSArray> *caches = [_imageCaches copy]; SD_UNLOCK(self.cachesLock); return caches; } - (void)setCaches:(NSArray> *)caches { SD_LOCK(self.cachesLock); - [caches_ removeAllObjects]; + [_imageCaches removeAllObjects]; if (caches.count) { - [caches_ addObjectsFromArray:caches]; + [_imageCaches addObjectsFromArray:caches]; } SD_UNLOCK(self.cachesLock); } @@ -68,7 +68,7 @@ return; } SD_LOCK(self.cachesLock); - [caches_ addObject:cache]; + [_imageCaches addObject:cache]; SD_UNLOCK(self.cachesLock); } @@ -77,7 +77,7 @@ return; } SD_LOCK(self.cachesLock); - [caches_ removeObject:cache]; + [_imageCaches removeObject:cache]; SD_UNLOCK(self.cachesLock); } diff --git a/SDWebImage/SDImageCodersManager.h b/SDWebImage/SDImageCodersManager.h index cd77091a..14b655da 100644 --- a/SDWebImage/SDImageCodersManager.h +++ b/SDWebImage/SDImageCodersManager.h @@ -39,7 +39,7 @@ /** All coders in coders manager. The coders array is a priority queue, which means the later added coder will have the highest priority */ -@property (nonatomic, copy, readwrite, nullable) NSArray> *coders; +@property (nonatomic, copy, nullable) NSArray> *coders; /** Add a new coder to the end of coders array. Which has the highest priority. diff --git a/SDWebImage/SDImageCodersManager.m b/SDWebImage/SDImageCodersManager.m index e358542b..2a25fdb2 100644 --- a/SDWebImage/SDImageCodersManager.m +++ b/SDWebImage/SDImageCodersManager.m @@ -18,6 +18,9 @@ @end @implementation SDImageCodersManager +{ + NSMutableArray> *_imageCoders; +} + (nonnull instancetype)sharedManager { static dispatch_once_t once; @@ -31,12 +34,30 @@ - (instancetype)init { if (self = [super init]) { // initialize with default coders - _coders = @[[SDImageIOCoder sharedCoder], [SDImageGIFCoder sharedCoder], [SDImageAPNGCoder sharedCoder]]; + _imageCoders = [NSMutableArray arrayWithArray:@[[SDImageIOCoder sharedCoder], [SDImageGIFCoder sharedCoder], [SDImageAPNGCoder sharedCoder]]]; _codersLock = dispatch_semaphore_create(1); } return self; } +- (NSArray> *)coders +{ + SD_LOCK(self.codersLock); + NSArray> *coders = [_imageCoders copy]; + SD_UNLOCK(self.codersLock); + return coders; +} + +- (void)setCoders:(NSArray> *)coders +{ + SD_LOCK(self.codersLock); + [_imageCoders removeAllObjects]; + if (coders.count) { + [_imageCoders addObjectsFromArray:coders]; + } + SD_UNLOCK(self.codersLock); +} + #pragma mark - Coder IO operations - (void)addCoder:(nonnull id)coder { @@ -44,12 +65,7 @@ return; } SD_LOCK(self.codersLock); - NSMutableArray> *mutableCoders = [self.coders mutableCopy]; - if (!mutableCoders) { - mutableCoders = [NSMutableArray array]; - } - [mutableCoders addObject:coder]; - self.coders = [mutableCoders copy]; + [_imageCoders addObject:coder]; SD_UNLOCK(self.codersLock); } @@ -58,17 +74,13 @@ return; } SD_LOCK(self.codersLock); - NSMutableArray> *mutableCoders = [self.coders mutableCopy]; - [mutableCoders removeObject:coder]; - self.coders = [mutableCoders copy]; + [_imageCoders removeObject:coder]; SD_UNLOCK(self.codersLock); } #pragma mark - SDImageCoder - (BOOL)canDecodeFromData:(NSData *)data { - SD_LOCK(self.codersLock); NSArray> *coders = self.coders; - SD_UNLOCK(self.codersLock); for (id coder in coders.reverseObjectEnumerator) { if ([coder canDecodeFromData:data]) { return YES; @@ -78,9 +90,7 @@ } - (BOOL)canEncodeToFormat:(SDImageFormat)format { - SD_LOCK(self.codersLock); NSArray> *coders = self.coders; - SD_UNLOCK(self.codersLock); for (id coder in coders.reverseObjectEnumerator) { if ([coder canEncodeToFormat:format]) { return YES; @@ -94,9 +104,7 @@ return nil; } UIImage *image; - SD_LOCK(self.codersLock); NSArray> *coders = self.coders; - SD_UNLOCK(self.codersLock); for (id coder in coders.reverseObjectEnumerator) { if ([coder canDecodeFromData:data]) { image = [coder decodedImageWithData:data options:options]; @@ -111,9 +119,7 @@ if (!image) { return nil; } - SD_LOCK(self.codersLock); NSArray> *coders = self.coders; - SD_UNLOCK(self.codersLock); for (id coder in coders.reverseObjectEnumerator) { if ([coder canEncodeToFormat:format]) { return [coder encodedDataWithImage:image format:format options:options]; diff --git a/SDWebImage/SDImageLoadersManager.h b/SDWebImage/SDImageLoadersManager.h index 651b5e9e..948ca3fa 100644 --- a/SDWebImage/SDImageLoadersManager.h +++ b/SDWebImage/SDImageLoadersManager.h @@ -18,7 +18,7 @@ /** All image loaders in manager. The loaders array is a priority queue, which means the later added loader will have the highest priority */ -@property (nonatomic, copy, readwrite, nullable) NSArray>* loaders; +@property (nonatomic, copy, nullable) NSArray>* loaders; /** Add a new image loader to the end of loaders array. Which has the highest priority. diff --git a/SDWebImage/SDImageLoadersManager.m b/SDWebImage/SDImageLoadersManager.m index ecb476c5..91e0d941 100644 --- a/SDWebImage/SDImageLoadersManager.m +++ b/SDWebImage/SDImageLoadersManager.m @@ -16,6 +16,9 @@ @end @implementation SDImageLoadersManager +{ + NSMutableArray>* _imageLoaders; +} + (SDImageLoadersManager *)sharedManager { static dispatch_once_t onceToken; @@ -30,12 +33,28 @@ self = [super init]; if (self) { // initialize with default image loaders - _loaders = @[[SDWebImageDownloader sharedDownloader]]; + _imageLoaders = [NSMutableArray arrayWithObject:[SDWebImageDownloader sharedDownloader]]; _loadersLock = dispatch_semaphore_create(1); } return self; } +- (NSArray> *)loaders { + SD_LOCK(self.loadersLock); + NSArray>* loaders = [_imageLoaders copy]; + SD_UNLOCK(self.loadersLock); + return loaders; +} + +- (void)setLoaders:(NSArray> *)loaders { + SD_LOCK(self.loadersLock); + [_imageLoaders removeAllObjects]; + if (loaders.count) { + [_imageLoaders addObjectsFromArray:loaders]; + } + SD_UNLOCK(self.loadersLock); +} + #pragma mark - Loader Property - (void)addLoader:(id)loader { @@ -43,12 +62,7 @@ return; } SD_LOCK(self.loadersLock); - NSMutableArray> *mutableLoaders = [self.loaders mutableCopy]; - if (!mutableLoaders) { - mutableLoaders = [NSMutableArray array]; - } - [mutableLoaders addObject:loader]; - self.loaders = [mutableLoaders copy]; + [_imageLoaders addObject:loader]; SD_UNLOCK(self.loadersLock); } @@ -57,18 +71,14 @@ return; } SD_LOCK(self.loadersLock); - NSMutableArray> *mutableLoaders = [self.loaders mutableCopy]; - [mutableLoaders removeObject:loader]; - self.loaders = [mutableLoaders copy]; + [_imageLoaders removeObject:loader]; SD_UNLOCK(self.loadersLock); } #pragma mark - SDImageLoader - (BOOL)canRequestImageForURL:(nullable NSURL *)url { - SD_LOCK(self.loadersLock); NSArray> *loaders = self.loaders; - SD_UNLOCK(self.loadersLock); for (id loader in loaders.reverseObjectEnumerator) { if ([loader canRequestImageForURL:url]) { return YES; @@ -81,9 +91,7 @@ if (!url) { return nil; } - SD_LOCK(self.loadersLock); NSArray> *loaders = self.loaders; - SD_UNLOCK(self.loadersLock); for (id loader in loaders.reverseObjectEnumerator) { if ([loader canRequestImageForURL:url]) { return [loader requestImageWithURL:url options:options context:context progress:progressBlock completed:completedBlock]; From 82752741542629824992d77dc55392f668a19766 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 2 Apr 2019 12:06:27 +0800 Subject: [PATCH 354/361] Fix the blacking error domain should filter specify SDWebImageErrorDomain codes which is indeed un-recoverable --- SDWebImage/SDWebImageManager.m | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 4d72ef0d..409b07ab 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -178,7 +178,7 @@ static id _defaultImageLoader; // Query cache process - (void)callCacheProcessForOperation:(nonnull SDWebImageCombinedOperation *)operation - url:(nullable NSURL *)url + url:(nonnull NSURL *)url options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context progress:(nullable SDImageLoaderProgressBlock)progressBlock @@ -206,7 +206,7 @@ static id _defaultImageLoader; // Download process - (void)callDownloadProcessForOperation:(nonnull SDWebImageCombinedOperation *)operation - url:(nullable NSURL *)url + url:(nonnull NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context cachedImage:(nullable UIImage *)cachedImage @@ -280,7 +280,7 @@ static id _defaultImageLoader; // Store cache process - (void)callStoreCacheProcessForOperation:(nonnull SDWebImageCombinedOperation *)operation - url:(nullable NSURL *)url + url:(nonnull NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context downloadedImage:(nullable UIImage *)downloadedImage @@ -375,7 +375,10 @@ static id _defaultImageLoader; shouldBlockFailedURL = [self.delegate imageManager:self shouldBlockFailedURL:url withError:error]; } else { // Filter the error domain and check error codes - if ([error.domain isEqualToString:NSURLErrorDomain]) { + if ([error.domain isEqualToString:SDWebImageErrorDomain]) { + shouldBlockFailedURL = ( error.code == SDWebImageErrorInvalidURL + || error.code == SDWebImageErrorBadImageData); + } else if ([error.domain isEqualToString:NSURLErrorDomain]) { shouldBlockFailedURL = ( error.code != NSURLErrorNotConnectedToInternet && error.code != NSURLErrorCancelled && error.code != NSURLErrorTimedOut From fa426f9b054d1b970d0d4c0bd094ca2c7179896a Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 2 Apr 2019 14:59:21 +0800 Subject: [PATCH 355/361] Update to use the delegate mode, let the actual image loader to decide whether to mark failed or not. --- SDWebImage/SDImageLoader.h | 14 ++++++++++++++ SDWebImage/SDImageLoadersManager.m | 13 +++++++++++++ SDWebImage/SDWebImageDownloader.m | 21 +++++++++++++++++++++ SDWebImage/SDWebImageManager.m | 15 ++------------- 4 files changed, 50 insertions(+), 13 deletions(-) diff --git a/SDWebImage/SDImageLoader.h b/SDWebImage/SDImageLoader.h index a69f7c53..f4de58fa 100644 --- a/SDWebImage/SDImageLoader.h +++ b/SDWebImage/SDImageLoader.h @@ -85,4 +85,18 @@ FOUNDATION_EXPORT UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NS progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDImageLoaderCompletedBlock)completedBlock; + +@optional +/** + Whether the error from image loader should be marked indded un-recoverable or not. + If this return YES, failed URL which does not using `SDWebImageRetryFailed` will be blocked into black list. Else not. + If does not implements this method, assume always return NO. + + @param url The URL represent the image. Note this may not be a HTTP URL + @param error The URL's loading error, from previous `requestImageWithURL:options:context:progress:completed:` completedBlock's error. + @return Whether to block this url or not. Return YES to mark this URL as failed. + */ +- (BOOL)shouldBlockFailedURLWithURL:(nonnull NSURL *)url + error:(nonnull NSError *)error; + @end diff --git a/SDWebImage/SDImageLoadersManager.m b/SDWebImage/SDImageLoadersManager.m index 91e0d941..dd99c31c 100644 --- a/SDWebImage/SDImageLoadersManager.m +++ b/SDWebImage/SDImageLoadersManager.m @@ -100,4 +100,17 @@ return nil; } +- (BOOL)shouldBlockFailedURLWithURL:(NSURL *)url error:(NSError *)error { + NSArray> *loaders = self.loaders; + for (id loader in loaders.reverseObjectEnumerator) { + if (![loader respondsToSelector:@selector(shouldBlockFailedURLWithURL:error:)]) { + break; + } + if ([loader canRequestImageForURL:url]) { + return [loader shouldBlockFailedURLWithURL:url error:error]; + } + } + return NO; +} + @end diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 6ae608f9..da244659 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -546,4 +546,25 @@ didReceiveResponse:(NSURLResponse *)response return [self downloadImageWithURL:url options:downloaderOptions context:context progress:progressBlock completed:completedBlock]; } +- (BOOL)shouldBlockFailedURLWithURL:(NSURL *)url error:(NSError *)error { + BOOL shouldBlockFailedURL; + // Filter the error domain and check error codes + if ([error.domain isEqualToString:SDWebImageErrorDomain]) { + shouldBlockFailedURL = ( error.code == SDWebImageErrorInvalidURL + || error.code == SDWebImageErrorBadImageData); + } else if ([error.domain isEqualToString:NSURLErrorDomain]) { + shouldBlockFailedURL = ( error.code != NSURLErrorNotConnectedToInternet + && error.code != NSURLErrorCancelled + && error.code != NSURLErrorTimedOut + && error.code != NSURLErrorInternationalRoamingOff + && error.code != NSURLErrorDataNotAllowed + && error.code != NSURLErrorCannotFindHost + && error.code != NSURLErrorCannotConnectToHost + && error.code != NSURLErrorNetworkConnectionLost); + } else { + shouldBlockFailedURL = NO; + } + return shouldBlockFailedURL; +} + @end diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 409b07ab..2ffe6c61 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -374,19 +374,8 @@ static id _defaultImageLoader; if ([self.delegate respondsToSelector:@selector(imageManager:shouldBlockFailedURL:withError:)]) { shouldBlockFailedURL = [self.delegate imageManager:self shouldBlockFailedURL:url withError:error]; } else { - // Filter the error domain and check error codes - if ([error.domain isEqualToString:SDWebImageErrorDomain]) { - shouldBlockFailedURL = ( error.code == SDWebImageErrorInvalidURL - || error.code == SDWebImageErrorBadImageData); - } else if ([error.domain isEqualToString:NSURLErrorDomain]) { - shouldBlockFailedURL = ( error.code != NSURLErrorNotConnectedToInternet - && error.code != NSURLErrorCancelled - && error.code != NSURLErrorTimedOut - && error.code != NSURLErrorInternationalRoamingOff - && error.code != NSURLErrorDataNotAllowed - && error.code != NSURLErrorCannotFindHost - && error.code != NSURLErrorCannotConnectToHost - && error.code != NSURLErrorNetworkConnectionLost); + if ([self.imageLoader respondsToSelector:@selector(shouldBlockFailedURLWithURL:error:)]) { + shouldBlockFailedURL = [self.imageLoader shouldBlockFailedURLWithURL:url error:error]; } else { shouldBlockFailedURL = NO; } From 691873117a21143da877d7ad48d350b2362571a8 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 2 Apr 2019 16:32:15 +0800 Subject: [PATCH 356/361] Fix the logic to check loaders. Find the correct loader first and then check if optional protocol method is implemented --- SDWebImage/SDImageLoadersManager.m | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/SDWebImage/SDImageLoadersManager.m b/SDWebImage/SDImageLoadersManager.m index dd99c31c..680b9a7a 100644 --- a/SDWebImage/SDImageLoadersManager.m +++ b/SDWebImage/SDImageLoadersManager.m @@ -103,11 +103,12 @@ - (BOOL)shouldBlockFailedURLWithURL:(NSURL *)url error:(NSError *)error { NSArray> *loaders = self.loaders; for (id loader in loaders.reverseObjectEnumerator) { - if (![loader respondsToSelector:@selector(shouldBlockFailedURLWithURL:error:)]) { - break; - } if ([loader canRequestImageForURL:url]) { - return [loader shouldBlockFailedURLWithURL:url error:error]; + if ([loader respondsToSelector:@selector(shouldBlockFailedURLWithURL:error:)]) { + return [loader shouldBlockFailedURLWithURL:url error:error]; + } else { + return NO; + } } } return NO; From 100869dd70782c71901b8803e5dec76e3f62a376 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Tue, 2 Apr 2019 16:59:57 +0800 Subject: [PATCH 357/361] Fix caches manager operation thread safe issue --- .../Private/SDImageCachesManagerOperation.m | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/SDWebImage/Private/SDImageCachesManagerOperation.m b/SDWebImage/Private/SDImageCachesManagerOperation.m index 67f41450..131a18fe 100644 --- a/SDWebImage/Private/SDImageCachesManagerOperation.m +++ b/SDWebImage/Private/SDImageCachesManagerOperation.m @@ -9,10 +9,22 @@ #import "SDImageCachesManagerOperation.h" @implementation SDImageCachesManagerOperation +{ + dispatch_semaphore_t _pendingCountLock; +} @synthesize executing = _executing; @synthesize finished = _finished; @synthesize cancelled = _cancelled; +@synthesize pendingCount = _pendingCount; + +- (instancetype)init { + if (self = [super init]) { + _pendingCountLock = dispatch_semaphore_create(1); + _pendingCount = 0; + } + return self; +} - (void)beginWithTotalCount:(NSUInteger)totalCount { self.executing = YES; @@ -20,8 +32,17 @@ _pendingCount = totalCount; } +- (NSUInteger)pendingCount { + SD_LOCK(_pendingCountLock); + NSUInteger pendingCount = _pendingCount; + SD_UNLOCK(_pendingCountLock); + return pendingCount; +} + - (void)completeOne { + SD_LOCK(_pendingCountLock); _pendingCount = _pendingCount > 0 ? _pendingCount - 1 : 0; + SD_UNLOCK(_pendingCountLock); } - (void)cancel { @@ -36,7 +57,9 @@ } - (void)reset { + SD_LOCK(_pendingCountLock); _pendingCount = 0; + SD_UNLOCK(_pendingCountLock); } - (void)setFinished:(BOOL)finished { From 2640301e82e4a0ee03d4f5d0846a3d0b02979697 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 2 Apr 2019 17:56:12 +0800 Subject: [PATCH 358/361] Change the optional method into required, force the custom loader author to provide the error check --- SDWebImage/SDImageLoader.h | 2 -- SDWebImage/SDImageLoadersManager.m | 6 +----- SDWebImage/SDWebImageManager.m | 6 +----- Tests/Tests/SDWebImageTestLoader.m | 4 ++++ 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/SDWebImage/SDImageLoader.h b/SDWebImage/SDImageLoader.h index f4de58fa..136ac9e4 100644 --- a/SDWebImage/SDImageLoader.h +++ b/SDWebImage/SDImageLoader.h @@ -86,11 +86,9 @@ FOUNDATION_EXPORT UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NS completed:(nullable SDImageLoaderCompletedBlock)completedBlock; -@optional /** Whether the error from image loader should be marked indded un-recoverable or not. If this return YES, failed URL which does not using `SDWebImageRetryFailed` will be blocked into black list. Else not. - If does not implements this method, assume always return NO. @param url The URL represent the image. Note this may not be a HTTP URL @param error The URL's loading error, from previous `requestImageWithURL:options:context:progress:completed:` completedBlock's error. diff --git a/SDWebImage/SDImageLoadersManager.m b/SDWebImage/SDImageLoadersManager.m index 680b9a7a..002ef95a 100644 --- a/SDWebImage/SDImageLoadersManager.m +++ b/SDWebImage/SDImageLoadersManager.m @@ -104,11 +104,7 @@ NSArray> *loaders = self.loaders; for (id loader in loaders.reverseObjectEnumerator) { if ([loader canRequestImageForURL:url]) { - if ([loader respondsToSelector:@selector(shouldBlockFailedURLWithURL:error:)]) { - return [loader shouldBlockFailedURLWithURL:url error:error]; - } else { - return NO; - } + return [loader shouldBlockFailedURLWithURL:url error:error]; } } return NO; diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 2ffe6c61..666148dd 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -374,11 +374,7 @@ static id _defaultImageLoader; if ([self.delegate respondsToSelector:@selector(imageManager:shouldBlockFailedURL:withError:)]) { shouldBlockFailedURL = [self.delegate imageManager:self shouldBlockFailedURL:url withError:error]; } else { - if ([self.imageLoader respondsToSelector:@selector(shouldBlockFailedURLWithURL:error:)]) { - shouldBlockFailedURL = [self.imageLoader shouldBlockFailedURLWithURL:url error:error]; - } else { - shouldBlockFailedURL = NO; - } + shouldBlockFailedURL = [self.imageLoader shouldBlockFailedURLWithURL:url error:error]; } return shouldBlockFailedURL; diff --git a/Tests/Tests/SDWebImageTestLoader.m b/Tests/Tests/SDWebImageTestLoader.m index 32635b2d..22978edb 100644 --- a/Tests/Tests/SDWebImageTestLoader.m +++ b/Tests/Tests/SDWebImageTestLoader.m @@ -50,4 +50,8 @@ return task; } +- (BOOL)shouldBlockFailedURLWithURL:(NSURL *)url error:(NSError *)error { + return NO; +} + @end From ec3b0590b07c81f1d2eac94e2cf24a18ea6e0960 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Tue, 2 Apr 2019 19:44:23 +0800 Subject: [PATCH 359/361] Cancel latest image load when call cancelCurrentImageLoad --- Examples/SDWebImage Demo/MasterViewController.m | 1 + SDWebImage/UIView+WebCache.m | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Examples/SDWebImage Demo/MasterViewController.m b/Examples/SDWebImage Demo/MasterViewController.m index fcedeffe..1abaf90c 100644 --- a/Examples/SDWebImage Demo/MasterViewController.m +++ b/Examples/SDWebImage Demo/MasterViewController.m @@ -112,6 +112,7 @@ [cell.customImageView sd_setImageWithURL:[NSURL URLWithString:self.objects[indexPath.row]] placeholderImage:placeholderImage options:indexPath.row == 0 ? SDWebImageRefreshCached : 0]; + [cell.customImageView sd_cancelCurrentImageLoad]; return cell; } diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 289c90e3..8f402b47 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -23,6 +23,14 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; objc_setAssociatedObject(self, @selector(sd_imageURL), sd_imageURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } +- (nullable NSString *)sd_latestOperationKey { + return objc_getAssociatedObject(self, @selector(sd_latestOperationKey)); +} + +- (void)setSd_latestOperationKey:(NSString * _Nullable)sd_latestOperationKey { + objc_setAssociatedObject(self, @selector(sd_latestOperationKey), sd_latestOperationKey, OBJC_ASSOCIATION_COPY_NONATOMIC); +} + - (NSProgress *)sd_imageProgress { NSProgress *progress = objc_getAssociatedObject(self, @selector(sd_imageProgress)); if (!progress) { @@ -48,6 +56,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; if (!validOperationKey) { validOperationKey = NSStringFromClass([self class]); } + [self setSd_latestOperationKey:validOperationKey]; [self sd_cancelImageLoadOperationWithKey:validOperationKey]; self.sd_imageURL = url; @@ -171,7 +180,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; } - (void)sd_cancelCurrentImageLoad { - [self sd_cancelImageLoadOperationWithKey:NSStringFromClass([self class])]; + [self sd_cancelImageLoadOperationWithKey:[self sd_latestOperationKey]]; } - (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock cacheType:(SDImageCacheType)cacheType imageURL:(NSURL *)imageURL { From 8294d74e93bcc611ab04f70209c62530eb0524cc Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Tue, 2 Apr 2019 19:45:40 +0800 Subject: [PATCH 360/361] Remove test code --- Examples/SDWebImage Demo/MasterViewController.m | 1 - 1 file changed, 1 deletion(-) diff --git a/Examples/SDWebImage Demo/MasterViewController.m b/Examples/SDWebImage Demo/MasterViewController.m index 1abaf90c..fcedeffe 100644 --- a/Examples/SDWebImage Demo/MasterViewController.m +++ b/Examples/SDWebImage Demo/MasterViewController.m @@ -112,7 +112,6 @@ [cell.customImageView sd_setImageWithURL:[NSURL URLWithString:self.objects[indexPath.row]] placeholderImage:placeholderImage options:indexPath.row == 0 ? SDWebImageRefreshCached : 0]; - [cell.customImageView sd_cancelCurrentImageLoad]; return cell; } From c369d70f1228c7fc10f92a14c72005eefa345a38 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Tue, 2 Apr 2019 19:57:46 +0800 Subject: [PATCH 361/361] Adjust coding style --- SDWebImage/UIView+WebCache.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 8f402b47..cb470c6c 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -56,7 +56,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; if (!validOperationKey) { validOperationKey = NSStringFromClass([self class]); } - [self setSd_latestOperationKey:validOperationKey]; + self.sd_latestOperationKey = validOperationKey; [self sd_cancelImageLoadOperationWithKey:validOperationKey]; self.sd_imageURL = url; @@ -180,7 +180,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; } - (void)sd_cancelCurrentImageLoad { - [self sd_cancelImageLoadOperationWithKey:[self sd_latestOperationKey]]; + [self sd_cancelImageLoadOperationWithKey:self.sd_latestOperationKey]; } - (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock cacheType:(SDImageCacheType)cacheType imageURL:(NSURL *)imageURL {

DdbMXPN$)=)F;o4%1yRwp`4SHxP00 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 Q?pyw?9`Ap-Z#n+I0d^;mN&o-= literal 0 HcmV?d00001 diff --git a/Docs/Diagrams/SDWebImageLoaderClassDiagram.png b/Docs/Diagrams/SDWebImageLoaderClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..3adc45b3ddd1b143677e883e41d5718505bd5f26 GIT binary patch literal 169264 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 RmAcjum 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�BHKuoPgT-9xh8SaOFM#Ul{134qT#=%76g)$Me9gp1gqu!1SHl zmB(ve)oQ|%;uiqEXzu;I0pSGr&|F}Pj(LGk39t`nsSiokT=?(g2_=bv?#asmFFiz~ zS&lsO^tg_EpUAndi@o0-S{^;hIz9d!G8LNC0BTz;+U=P*alMQY0I}OdQFG#|rXSRJ zPyY_TmRJ%28rv*R7!N?sv&=YC*{#g05gRDz7n}Tlez9;5;a}%0zn6UX(wU-}-+2SG zb=u8=(CwBGQbR5Vl_Ec#l#_7oBXtIiy}y*)s@CZ0KopI=J!H}5y9tudxboN__rysk zRsy)etN~K8k(~Fkneo00I{;0+z~%hFTW}Nrqrw1yo_PzLHbmvB${aB2pmyu}8g|yC zE=zDeu$mpEikmCSIH|hiSvX6b&jCgz@n36o}JRwOvxa!_Q7dDKmw?E|M zUNdh7<9}QLxtkwZ_SNR7cIhf2xM^75f@|wzrgRq+ZiW98r`Y|ISV6Pp_X3bfq`Wmc zw0lz~G<++2qZ({cUG6d#0zatm`T@Is3_gbu84Szo7d;=mTwKVpq@vJ6mWHlq+eoAr zlBEKs#)1kjw?nBYY8dy? zDPqPe*83~Ar@~FDx0cx|9JzPXDg(7jS`M{O4cYfj3Pv;pEygc4S347yx1V_4)vn}|CYmF&A5P&jl z0azLM0Ip(rbuUT8N8mlM0PWlE-xpu(<@V2mJW%>_D!5 zC?0S!!tq-1K99w0O1dDnhwl3ZhYs>61LklwgG0!KMvr4pJb05r&VSowzxl=kaG*DW z?p2Qybgv%A2RkVlTL8_kQ@ru)4lOV!ebXM1U!SS$SF-}xFB9S9(F|GdE+I&s`PAL{ zMtA2FC`2CAO?br(dxF)hcl!3hZ?R*3twjLx3Ux-L+MXVa;&sEO0=5^YZ~O~!?LuAc zxXFe8xvnq}#5Qp=Pyj_kYA|mN1ygygH|@MPfHZ^#{Jn2)fk)~cs}A;BHGu-bQeK3F zhz@o@t8i`j5;*0xjQ@a-a;sPEEe^4v$O{lNNF&dVFN2yN#sjUpUEO9iL7>q=i6fA7(a@jTz zHh2LgosQL&_zYmW5lq$sP?9L*({S6F8?)}#z}IS&W=HFLA$Raozy@@u$&{IP+-A?~ z;*L7`0cVa*`1Vg_m@|Dg?z(6D8?XzKvp}TQNbE9X^#hK`yAaV_Y3+*_rkF|iZ%UY* zhI)zL$xC9Cg79xBo#$_dAJg9&4*8cTn9v&1#w4N?6-vw@htF6aUK683s?L@`OM^jf9Q-SOAS1C>aWArqdomhNRQc7XSO zytq&5rI&NX2~N%+aqw)BrxKoRUVSi_FQ&7_vbMN~9A1Z%ZJSsQ0D>hc3RZ}NT)Iug zxs6IXJsF|sbz~@$qsc1x!GF)MAy9n;{bYv2Bubq{5U}xkYp<|JbWmZ^sGNc0q zVsA8u$WE%eazAFNT#qJ2&k3#ieOB4E-aj3Bp+B$4Fed0Z=D4#wqJKndTxyUhrA7S~ zILYt@$kLg@(?@bKq`G;VrMAbeQB6}|Gp>W*>jNFu$Ra^m1W7=P5uQq|n6yVy@O9#o zA~0o?x_J=I79nv0Mu29gC!mDWM<;;9^S%rrXmiJ3m5kGe6J*W`5JNQ!*1d!jujp&G z0Gy+W8bQHbkWi21SvBmLBY%lp-vb^=zo0-lvHG6`-?TA;q3i+XM*_14gd`_fvZ?oR zL7pydOMd`T@8qt}3Zw|vn*tlgB^$a&>q^>c!X!a;lAM*8bu!y&c8r|FKkjaD>gS{S8NL~3SqJ&Gnozijftdm`b z-nbeqc**Y@29wBIHO0BxMHFokm|bHu~CBkT6a15{A?v0F>SX z5TGaI+qK#V4aH7Gl*cf6RdTa-@hXfvF5U1^&k$=rpnkDV$FXp*MB?vMWe*o{z0J;_ zf;_0;X7TKKPT)m)?L{3}g+vjxP8rkR&l$Suz6XM7>w$|ADgFIGP@fwbkk2GOH@XO` zg`5(ox$=9|<)6(-;5E6C)Rus1WN{AuBT_2%3?0lxI=iz!uEOCEdRunM@YW0!Hy5|f z%=Uh|nna&P=>lqm^G9hMJrQkvl|Z(HeOS@*$RDXXM%%pDggGJF|3lYzhg13g|Cf1= zdF;(O_RPr4h+`dl7qUm$p=9r4Mvg;>j3Wx!rBtY_oT89YQphS~@73>hd%r)Q-?+ZN zf9j8}tLwh+^BT|RTg#K&!ITstJMX5?NclIU%_z2>QR1+IY0{V*T5eR^lH5*O)?SP^f4P1Jxl5wyc%Y%wi7DT<2svxW%`C!<5!gPz z)IbI2NKgJ^1;WT>L668~+#KI|uBQJ2o^m)P=p{G^$|WCU9j_oHv4RAh&iU+UE{&Tm zT@%`HbUFOom)L#rYq8s?K=XCYyxHaL5*BrDgGw@fdB?!!KXge0G@1o zx^~%T171F@iidYSCb!L6nMKaF*!11+$v^)<7=wRcR=NzO%L6*myWss!Hf1i-|Ko~3 zfgUfb=go)-uaS4BFv=BncZzr+{ea<{pvoYBck!YHVO5p>fVnee^~;*gyCl)@X5ntl zJB)_S4EkrP3)4EZPyHs8IX!&&k&o8mBZn_&D8>^RtISt=1@ZG>%+GA2A|3>jJ#UdJ zOp4mP*`;l*hRu(c!oKUv7U*$iY^Fs^y}yhsY{V|!v-MW33I>G=uj*5r+E6z?&J5(O zGF9#iWU29^q6BSSHTojnofFG<6Eu6)pS$%D+&2r1kckufZt35{E07F1%?|XfA$4wA z-!|qygs!x0-13XrWz;!NCu6ev509tr1%wV4fe<~rK zv=(%iAN_>?h<2@lo)sA>3R4>uD5rpNzaE*{w-Q;CGTUk^?f=O)mq(?A{tXd~*p} z9EyYs6Vv50~OH4A%q(2co1jyMAWmp^w@ZmA7RHWnt?sE6gwq(!U;?&`ys zj}?~Kw27L(B(R*vYB)5uEhx3`NHnaGKJ`{oN3Un4iRF6S`Sgv}XFaiLqo9X^@otY5 zqG*H=8!CQZ8hPYK=AQgCvTn*&6CxR|0Tn}hx?b6PgOYT;QHpyLx3LP~4`9kry0s zsr81RJFGy49ccnxc84<7E}k|-vu(1D$&iBNOc*j=L0oM0Q={_8G)^u|BYA&XL{e*u z$%nFBSpMnbL@J&hI$q;+frU~~rW4iB%YjvCSBBzFlL9j0AAerwpg%oQBkQkfRiL9< z3A)Ly-tRp3zv*MrCq9QW>D29&#(oaP}DfvPOc|(yn3`q~@q=q*Pw0 zy4Q{5S{JQf*%T;jBx97u%8K6|9G9EG8Mv6ZMq#rE*Gc#=jUeOjLYCPh-0YKKBZnrj za6_6Z8|b%WNz=S%0>=xdoefGy#Q>{pvkepT{L`(n|GFHflIoEwZfmAwOU z<}%f#7vogwOwRYaz2OaQ&sM9{99n=N3`2eBa5B{oW1qWO2{c0d585Fq(yP6j(jAC2 zF%i0J}u`wBv&Hc#ezNJ$iReB*GaQ1)G*WZcJkB5j;n? z{N@_G3*BgZN!5F!Cc5iYk(Ks&D+fY!%i>9+P}KnS>ficDIKiJV(8rh2L0t}==2Ky4 zsJeu}2!)r#?0f6KeJ8n)C(4NlA_i*O8&o{(hHtpk+MzZhZqshO%9v5GrZU*D>&sY0 zW(~KomgH3+ARl`%L+6@?sLYtj1fs!=-pR7LE{tZklMHnB0XZAXp8y?>RwL=#(ep z5^4;KF8<+a4i;RhT?F*SCuPt7@Sl`>3#un4fcF0k8bfXAd-UN+Tl#HA>kiFnfH~&9 zboJ5iJ&id{Mc><|cb_7?_rM91k+(MSxg2LND_bMj|GGA(r0YQakId zw#ViE_MxuWKq?)xVo+DKj z0ekDSjH7f!rWz&z?VtT9d-Fqt-X~DGvkl+~>^Z+Xouvs8_ki?iBKNLGF>i1m%KM{t z!wHIRzH&mI5R(IAsed4QV3tzi$W;U#mQ(;ApbSpLiKTK&0eH7o71;L8YVp`~1NehW z$+eSg=dDBoM$`O?rbZH3Oj*$&fHdN7x?5`Tg6Abvq zCn6T5P)ffpIYp}gyIiJun@?gD3Z5FsGV=#z{jS`A0{8`$VPqAY%q$bsAVJjr#W_>J zI!DS#{>cVV)O7#kjAVhVBr@3*Kx;(2`DYMo*~a)*f0rGLvP0S4B!qkLl=t$VeFIz( zxTmbJjk<3L)2`glopvu(IqjGG((ucUDCMeEL<$+xR&x4|{6h?yy#)b#17-i;=`55c zBq~y#WX`K*`nkbb8Zex>cyrgnhtLtG%>1H0F#1k4dQTcxb8M3)UH@H`kI?`T&AVi7 zh+AMtfHfx}&M+$<(p97PfEgqYMKF8M+D69N_Xx&QJ-0OCUIM&OwXyISKGd6EZGaZ{zP{D4i9iUlLEATUCyP`d;SK9-d@oN1H>B1PM)W?7a zM;s^oBFRGUuK|lsGTAG4QQWWjgxJ1{A#;$Xwh}ne+Lwc4KUezmFH=~cfhj~ZLcX8R z)wdQ%x*b&kN?=rbu_5sn)s{(`{C@nNoSh`V*C1GJ`Q!+pxzF3oG8W8BgqQn25JHJQ zZWvmm`V&bYGB$5_Elco$yGg9{S#t^06Mjb_UJxhWijUlXG)y$w?kPw13>PIY?@RT+TH7uzL&B2qE-Q(s|zbQRTym&O% zU81;^9*n2REfG?986~er%jnlWGA|Z=^6MTapD*757%}_OnekE;G_j&0qt=D%oH|F4 z;pk{9ya?^a^T>yn-kr2O%voSX^|)V{*3dO|I`5Stx^1}5T)4|W5Zk~kfH6YjT4?{MYD5_rpkOZ=q=gD~DmpeF5;lPu zOS0TYMd+og;3U<8^jvC(p;57U00$X@QaNDksSJlVC}`M`g7k)PW;TRkSZmql>r0-H zoBZXZ8WLUl8g3Jt_oOO@9JxFNbNjAFh%^7d-nbh)o(w40o2*j!MsXYWvi(R`Q;vaer8ViE)g^q<;vk)hW6RKZHUFIrreIl?VV=;k(V*tF}3xYn`Q0@q~^h zJ(#~ckGsr|M^`=+wn_hS`seB*Ke@VSLGkMFlR6?N_tdE*cqANu(cHYW1i*!KA!p!n ztK9-iJS}n)T}$yuDVXEDYHmB%fn*!|*Ox(q3II#hZzlPxs#wpn9fj4sVp3a%d6Ru1 zrkSi`!uw_{_XUg96@l*3XyGJnQJY`FLh-Q7#KanNIr`ki7)AyVBvK8zF;%PA)(L?p z5_LY&{}ZMjbmlL1CQ(0h{!C+k=sNrMHeTu`ElHC6Z-f%|NVBc+x2DkaL7q#VQSrjS zJ(iEGB5DZDT$O8ceRIGCrjOS+9F-6I&acYq!I+d1&>!Mm)Pdc{u26fBkR{+%#?2i4 z{C?33G6=17Xht--qOME5|JZZ!?XJhIh#A~k|6kQ2#Y0zg@4KLel(E%OEy5AZ^%kdu z{Dc0pHBz*r?(MaJv9lV7q51SIeB-i(M-wY(Io>JXpEf7YcXIY>ci~>(;^;6h(;W@m zi&3-v02Md{Xfp*!0Af~}m8JF#EaRzPTB*VvlLwiJRNIE2!fz1taxv=;^#RqHBM9Z{ zxf%$-Tzphqq9om{vPZ%aia=fxh84dScuz2kH$&&!9i^)!SbPejwV=?2)g9*`arg6f zByauINQos8fO)POwYAF7ZGVd76k`UdHuLMM=h|s3%GYNmMFY683n}>UNo@`je*8D_ zru0xWM2%uTIV=D*Ds5)SXU%u&9d8ot1Eryai!`o|HD88CQSkCuqebx$EynElo9Gw& zv45RRtIW5s3t5Xfm#MAJ=RaS1xB2^{Zgan0t)-zCkKlmV2FBID=eBvVLQgF&LOWU@ zmzwk{reE-CW#RVF@(F-k_5{LXlq%c}N*;H!8Ng2=CCw*sl4z!jh=}*`Tx5tld=_6< za}pWaR?M4MuL2D>9iAe%>wMK9!h>0^Bg?Uhr{gbdI?E_8JJjY|A1)4eikPe4DOa@ zCZ=R_;oUS<#oN0Mga}lwKS7)aEIRCL=G8a3!PK_^9jdngblY1&orWz-gB*?tW^7BJt!_Q<|t}t`f1|DWL zEdK$A5j@hAA3SQ=E+ICED2Hd1s7UhFy{#4`m{k)%Wm0?UG%F`1QKxT#Bfmd!h7X{x z0oX@&)sE2Kc5JItfS$?>x|u(OKXUq)Y{5?Q>||3Q9^lo2(xj0*X!t1^t6ny`zdU{1 zYTn2j7)-p<6y$nt&2hfNAV>Ha;3(K-6d1Uj7E5e!xQnOcCvADuk-Q)>LWkP7W0aWD zT?d;Xt{a{Sbjbt{UhZGrLJUOzO4}Y)Fq_Vjf}Nas!%%tp|IB=$*5omG3_@NG<0&;z zle)3jlHdNF#O5Tb5roqa1l|v`AXi{+wM-T2GanaF&U>Lr7LX3qXFVCMcZsys5h7rOv|Kl-UPG4DgztOaA__kIkiav>l*aJ?t_vD@sOC|x$KT9 zvCX-ntA@WW!jC?S|BAa+MTPmn)p`%^tN^k{XEGqDWWFavnBlrV48%&^_j zu$9d-z0O+wJLAu;eNShR&_Nrwg^Skh{D6Dv}r_c`>7E5Nt2wD>3GDO z<^in!)UWEN<&Bi#qANU4f4ngmhKt-qdZVeO#`1qDx0Zg?=x5~69y_cUxVN2|`_Ka} zA@9p^6b6Ps-=UFRTF5B+0>YTTNWoV)w)`(npIuUqy7y*M2En|4>D{Asr%U6MNC#&%iKH|m_JNQs2IHj1pD2uKV5W|`YL8#psD8&OcW}&)hgB* z4|RA#{*q4vemi6-g3sH89^?|tU#Y-6v;sY3_4{Jg7iQ;=tmV>Vc>~pebH{KEZuH}v z#erUide9*va?~l(-{(6BPD|>ieOt>F(5lr)enrk5$C)R|fq8G>Ye;3g(DErX+bGM3`09<3exbZ*)Ei;0W&>IN-UYb_9=h^W~|1q+%mkckz zj-B#8Jpn`mH$R->kj9W3xjMRv|IW%rXf%5^))y!_b$Q`m9{o0pWxPEI5&?xA5W#e% zr>P8udwW)%*Zcl)^rAfxBbl3>w4-UV|1;?d6nNdV^nLogUWzHj|KS3JdxR8uc*d>1 zdYM#kH5wPYSoajWgv=C~GK0ne2$Y)gz2{ohgs&VJyZ72J?zdG0*S`ctcRDH~KuQ|E znykh@o|1A5nep`rmyTG3Q2qY!TR@O`fjL*j;f2fV1fI@TWT|-*_TSbrjGZi(HCG4+ z!@@uUgYAfh!I2kefCC+HT&QtQ1)rJ!i{HbjL2>#9cp|DM)=sJrx^xjao&G|FcMKXK zfTw3vP;{P-hkklcW$G#+0$8L8csN#F6%B`IR{m=YO7j zt7xdIvb6&0qih8jN8<1sJ^>%8&iA$#!K%+5^;!fi-1S685N7^QJwF&Gf{uaZHs5P65$O0z$EFB~LIz_jAs^oj916S1*?ac8*R2JkgHU0NTSsEe>6t#<7q4@Xcj z-%d3Dc?JK0<|r1da3l1(=46>mf_z*p$VDy2A_>86he?~$pdW$XqPDSwDW%df%Xsw0 z87C;m*T!YIn4)dhLg(he8IQ2khs$E*mJ`cdJ7AZzb;<8kY&-%9nB5Uu=U_SJ6SPPy$>?~Ss?fXZ96rl}q7WNn zOBLIv<>+ozcn6DC#EXO!E|GwP$_sgN>+0l_6La+CNEc?}8o|vbbUJ^(udF8?Q9VFy zfV99TyMvj3L)*T6{T3&1dOmyQ2%>U~=^*oFri{`l{W`GlkY|97gca2iO58u~7S~wv zqdoGS_BAl#(0P_vO0~1jIYUK|XP2A+Ji+xyPU5{90^rWR1^!N$19+2Ws|my`Rwq4O zL4O2H)L5>0*sQM(-ioE0!LKCc*bsreF2vXOAzx1q>9gj*+Z>7X#-Fq8|G;1Y4<uNrmb_L@R?w-tG``--hU8uGhU{en7(^*A2deX)4`*sIo)U^D|9V!%xZhG8Plk6@(>uw7e4YFb9rf^ZqK^#|UZjRfJa=a3cq)yFlg;}}PN2XN%*r*&pIIXC zO_#8>$OF3$ypYt#d^23xvRH)^ZCd&wmtfZA{^vi_B^*AKsP~wq%Bb$MNO4B=2;*Af zo+)aagWQ2Lc-*pRS;Q*<4D<3ONE`uwkUA z+t&v{foz7?U&Um1Y0#0WG_F%e^Izv?p*z0S^V!4_j^Vd%4Ws&rN)xxwiNG>SB06~u zkB0!9$HRE8tnq$U5M1}mw_PIg`Her%wcG7h(P9BY5U2Oaxs%0<(MN{lWLuMKhpgPNWNK(7Dp7v{07!B%s%q(D-mTnj9d z1yU0tycre&!W&r=zW~dWhfhGUBAt!F?=3=y-Xi(5`9$Ap2ymLbaPYG+z6(*bmm%T% zxfU4Web)@8b#?Do7vw0i=>5>k$ijh2JZ3+Vo#dH)spsf73|qYS(!*~$hAIRl^rqrj z!Q;)}S7rYpPsXpG$V%qU*btfWcYl7pQhK}VOmk5A%X{Bo1{56%8=~~tbgRk(poiX8}uY-kR z9{qPE(Ir9q#QVDt9o>@yAB;i%XAI1*6l9Yk8fxvyf0r>u|2EqMXO|cg2^f-tfnn4F zl0~^9t|BgOuv5!kl%WgcTd}m!e=@2vb>_KA$!Ey1UuGu_|28iZ(4EQ<9LJjfD{h9% zBDPJ`4O@Gqx=5Qtjp@jPW~dtx1ZOor&^f3eo?l(v$hj~$YVJnEY-sT33WpWSKwPe_ zmFgK0Q$lqI!<7t>_?dLg070{ocD(_RmrhIWs(81;wmKFTcrF!d|ETfP175TPgGQei zl5rhmUEQ>=xtrFtk8Rk3%n!vO7Itva8_@46OQNDUY{X}%7T92P=q#im8qOqaRwC(? z9<(FdXa?7RYhZJ4-|+y9*kny|lzE;Y{qFQ9IWUV}Ytqv5t&BmP zVn|uyB%Uq$uy1Rt4UMHMo?NkdaICl0)bLs4q&HX~fu2}fJ>)M7TYb_3bCN_-pkN<^ zoH^P@P{H)8xF))nQVP#&*Rph@0Xhx5R)tt8+FcI+2F$xPLcnkf-19Q9iU2uI8b(F)lSeo? z5x$&;p5qb%oKvmcY(UL)kK0sJZSv{{V1uM8m9Cs-%72{D_j^IjP$2;gWroH%#@x`9uoZ;Kx~%?s?C>6Fq1O*}E?C zx>E2!PkLQ+k1|c>ut`ve8Rc;%m!@1eZ1%~5c$u5ky7eo;F$8!lWGKYNdA9S4^MvyI zj}9l|AAYgX{Uf#?G6-g1FHyV9eyj%B_)X;CRk6!PHD?QPQ@~W0K^iF~dPBNx6}h*!qrH_yypO`p1-BB??qJB!)JQMYQtGE;|zw!@#o%{jp1_5 z$=Zm^EQS=>p2mfJ{7-LRoP(%Bb4*^}A)=kV7V@L8K>d}dY}Zq%W~NS_-=6s2x?WJh zBITJ*9Qze%A~PkQ8Wyg|<54YIF_UCt`K`Myhfp)JVbvG*r*K`jjM=w^Ib?(-q2<$# zo5sB1&;xTGZ18%ceu00<1Y70Z50;bJqdS+KqCXykTI=oY$J&kxW3k@BB+Rlw9asVu zZm?7Nsk&Wc^X3dCp&RC%DkPL$<^4V8TautH#^`uzG(VSJK#W62>`iX6zjoMnfFH}e zQ`7^$dX*T7!kEWy<__@9{#hjb@^HOyTP*B+ut)!avMj&pbL*ZJ)nRATq&{;CXDW`G zIWU*)eU)@M_bv59QDN!!O}tty!^gj4z6}O>X_g<%96uzU?=9S{wB8!2pl^wm=5qdF zmf=YK+gsL{53uPx93*<|rF3~(GBclCG@kHnPTstBYcTD3Ne;v*LMu}#oXfhTUv(;= zed~h3QEd!=_<*bIHEUzO>!wwImtU;hYQHVRn&Geg6~3`hbfXtA9WOtw@&)P>@tRK* z*PDcFtNMwG_y=wKcAPo7dr;epM9k+@SBNp=2eed-Z~tQbxFP%I*umwAMBJ z3vLd;Nslybu6MEi`Xcn|#q<{Y^m7YT-_Qq69~CM}uemsnUMuHd+#7$zu29!qC(uy@ zJ9?$+4)FxVia##AU5_AKv-bObPQ+thD|-VXN&n!o@g~kf?R=8vysEPG`U1!i>3M&7 zX!ODI%k=u8fG_aVMvdm-H#;#UZ;PzBvY|;OZ~TY}1wjcC>@E&hzN4!XczVU%@IM4M zRp3O9otb)krxpPii#2VgwQ|DI9%l>WJku9Ps&lmY-;wfuZBkD2{1^*r%Xi5C>^1(vs^rH3;jsugEV>@`r5M70pmK)nE7 z?tO{pHeRzW*<5rK`U_c@eo6r5IF6yeoU2Ux5x;%Mxq%tBt=r=3#Ne51{kMgC??XGR z1{dDI)*&a_mN)GcnL?SWLPoLdkIwfVA01H6`wmwa3{xD<>2XQ@g@VLoIyvX8T91J1R>l+C_MgKOY4)7QyM=ukbAs+(r<5Np4n8dm^?>)?5%4 zIFlse(WOPnBS=O`?}Om;Ys`M{%juI!(|0;oRLu`!uHv&#H^c561Le=`)C<7Y#fP{8 zpuZki=C7OU6{~S;Z?9?^-Jr0v-~|QGr=qXWB5)gH^S|<=EquAa{Z@7@6Tk+Tf=Omi zVX2Cyz~Gtu;1)xv*?Ltv1>-C@f^UEkTMp$LXwsQV$6JoH4%3`L362QMMe@2K(Z~?< z4hNu&NMPHQ3*e!gq7GZZ$&%KF{TixeP#bg!!@RU6cJD$$A5^pX;p(fiz^jEr#7_Fq zSNq{y`_2z)H-qAd-CiZK(EZmfxJZv(q*_)7IzXl#AT<|vq`hORvLdGEfaBFLedj}9 zH;P7>7RbDAUwxy<=Ct zm&?1fS8-IhwSaR#xFaoGhI-00_V8IUnMZU_I~!6N?MpxWse!V*(dOZWCf{tC*Mn`V zPIT=QQ|Uffg%9(mcC}*GcvJ3@oGmRAn~CO8dRf7EIWu7cXmUMyt;KS;z3o1RSoO`5 z(vJ}KX4LEGe{U*0?kISJ9_9B>(zq91)j)r()86ISjw?!IBfRgx#KiU}+zPLMp89AM zX}(9tPnNNyHoFg2O1f3f{b;?E&l<^1gstv*-(S~k=>>n~WUG0XBJVhxeUJ65{|cNo z#o58NFCG@`?*+AEa%65w90;kZ;POh46BuksHPu-yF+)K`qPVCwh{mrXGf7e?rFg%H z0n3zZN`DwqaZ~Np29xEfhSLi(e7rn3`9EVVIVlk^Ix3MO_Uq*(Ln)|zgb$@#T#CjB znjOBL6B({KiIN!!wZ_IAD*7xLAe4Y(CPIjhC0!1VV`|BFGA>^|k|j%aq7P_-ouAiu44&se0t z)=k=UD_ar0ku+xb3BGwJB^G9Uh?XDMSv26vsc%;vf0M~2a;^MYv3zW8B<4YD%P6qw z=J{+q`~^9H-sl{oZD*aY?EJDP3F&u52dNyDqGHMp(~6u&T%#0m)#M~;BW;MRq};;# zBD4k{M!Wyutb8d}T}~fCBy8#0S`mD+cRYVxGmU-|Ra)`9km<5H(oL6jb7f{07P?CDgT}NY8YN53rjsh+_?;Vw`$@C zzPYGUQi+c`K%UMa;_BnV zIa(qfZtdN(GJa3*eh*#^C5iF~iyPF~-AF4ZsZ1@Y*XR5EabeR&?>Le6PWNuH0!#xT z;8JwK_R5grR!QsVb;kwv>HT{IsdIYE@Buc0EABe(TCM-zDY4%ug#d@4mbvNrqfgIF zIk^Psb#neXeQJ5IBJ#4NqDkvGc}__FiebQaAQD{XKu=x8wPC~JRrJ0mwKd#xUkkFb z%y>!gx#yHim6U5)S5)zV62sfezN4`|%2%35P@de3jKyHZw)AYFDSS@es@w--UVK=N_?Ds{mnCwPlTuet9d+OfP(T2!#b< zb&NUPf4Pb*IFr~h7D~?rKvVK(Fi+}f&6fMX0p-5IeunulKV4|9T1;$?=^i{fUMKTX zB!X}pDdp`~5l1^fjlJ?qVI(SOI{8=6%1wnjGT2|ULXjV%9hP0C&Ngokk9S_Ov9MP# z8H(6234bO^Dt6nqUAQdEvcO$X^?;pEt*rLQH5UwWE{Dda|hLF#~O>jDPS(XR@`K zI;6`ZyT-Vmw%Ei%ZS@ZXKz+q(RRdhAS(3ZOq|J zCb)@HL1-aV0gxF|kqtyts9_&5x$D9Z(78Cd9J#I; zfl#E#bE#=%+HMA8`xTEL3)9e?%BW^T`6aasy=!%eS{Qv3E9@qUCV9ewTXS88cR%r& zA8JFpn4ls&o@vg-+lG3wD$FV4qNzZ%>Qi3T=u}NpNvVheR&qTVs@@rdCxemBd{o$e)X>WjQxzSC}xTCxcm+sS5@8mv38o8OQkI z^Q|Sc_$-sh4H?wq+CSJ(k`@{a7kazIb}f`WrwMmxB>UA}$uiQ`Sme%Q=XXcPdt}1tjE5QJTY>{{ zUkR+L(*=t|{EussY)`je3E7)@`BhD!Hxk%vezo94K7a^gPZL*89><3U?r9zOH@J3w zU}wxXX5B_(^Pv432hv&gXa=-4kMbU~q8PNn{uQVi047x}>LP{?RnOt*3z>WOCRBqK zVe1LCH?hH9idDhK%R{o)PN8>MCTL^CHaCpmZjJ|pE#@7S@`;xHBg}!`y3R#+VhkvF zdc>+f8n;rM*@io$PShoZ;i&${9AMUwmdm#O4Vts7GB=&eP7q*u?b@(wWvqiDqCo=HPn zZgJ+n*e5uZkC`mzK^BnMxrzR3Rnm5&r_<@?Za(>9?IU)X`*?iu$nJniske2{@RDkb zx`DeG*$#Rxi)k4B+39ip;1^Jc92qoJPFeQZmS1C6dP%sk;Pc%pwz>a`7hSsD&C0{O zMiDE&e0%!gBHNxVES#)JmLia7mS{iGsAGNrBX5N1pA9{M7I&hn_vdj+pu zoiaALW_4tBqvNOydYp{g?HUHo-KzaF8}2-8YnT*i^4Y1xz2VRE#fa~@J{rDUPus?{ z_tKi-XKivRFMy*MnzAbi8ANHVlpB!!r1=31WimfX7tUyzw1${IW17CdSRUFeW*s*dbS7d#Rd-%rFglygwOF)-Q?8M&+s6BSx{SKL>0upWA}@ zu0GoVc4y<4Wlmte+a8b2EEB8j^_YZcIOY4a=Da#-Vy!K1)A-}|O%(N3mx zbAP&C{6wvk_v!0iHGk%*;d#)x%(gWK(7 z{t1^FIWHHChw+~Y*S5sR`B`~|eu9{PBjgL8??Z(T7s(wZjxEo!0(ed`$4icZM*N7< z-+e${cw7~^!F{c1TJ*8B9|bWt9;;gCa`zpaz15}GwolzVWNh)@k1%@^)W6RL95c6_ zgM`PEINR8KI*W7L_(83lew~oKW^nYdPVn@zI=Y9-snCc-`QH&qnO;%G=EBCygk3+H z1B~OJcm9B96=2Zb;rCSzprCJTLc3qafR6Ul4qoGI;e`UL3Lpr!X};v05$YsBm3i;} zpDkcuQXJR`=btc@=wAL%ta{P1l8MbZRrb1l@qbfb_Wse#UR*!Q=V+T(ym%o<9Xf0x z~ySOYlMaPkiTrF;^LI9i+l zv%>}UtH5zl0`gE4Q0)S$@i}(YVb`Cp@+IwlwhA{eD&4Yttm`uZhTG#uOIOYt)!rIF z=~V$dED$0*^xZ>!045e=me;!=Ee9m17S)E9oBuFaO+8QiC{}v-FOTL6fZr;2y4J1~ zViG=K0RD3bilpXykh#fbCJiklR*&5Jbn$z(KJRY`eisW81OLXtLL2lc@=r^Ck*s_2 zB5-f(l3ArZzZ;(zrX{ux63PuM(}9G;9$klDz>;yOg*A?tgo7DN<$L8|Y=K`Nt+g_a zWs~%00x){Sv09(i`{iPw3n`Y<*ZBUt+#EK#mBE%#gm%~m6N_0>wKW|j&$rBwm1D|C zYv{@kH-}WJR6jXLrHa!-%5QcSL{j$*xsg4n=0Z-^+*B## z`|An32t?hXlVzIts2;jN>QK1n#8jgxqW2Iaf5(!Oy#a;}JYN}*{zz09P%wMfo0V$Z zl7vkh{MgY!C5%%0Fr>0ASC#;g^0#GRM#9!&Q1!kcYE}XQXYe<6fQ&X@rhFx4=LMbI zJkZ+%?o50mQc9Ww`Q>lJTMwJ=d61+) z5bNB3+(tFKPOJvz)I$E=zVr^5e3*R?Fp*~@^R#b$zElqo8#Ea$x3YPz(xwzOku*LLpE6iyB;7tz z=lrtc+;v|_%O6mD?Y#;*RkM8c8hE*7i2dHStIvn@2A~<6YK+WqkY+@@u7fJ>EHEjs zknHd%Z3Xz!!+G*@ieO3>dMs@>JC!I*roW)24U7j9ZoA!&9ew87|KFIxlLK3Eo<)EC z5V+_BnW=ACzfO~((#kuxrsD?yOH}?!pouJ?Kh%#0RGkHDs`~7&I#+0O3P9KmuPJn zK{y8q|3iW6%JQHopfFUPVLrz$p}joF%6IH%h;sCz4^EMefaL*?5_KlxwdqVHLmuF9 zz~p)Be87J13X~-}C}ORKwaIp4?(_sc#^u%ttLK0WGhte!`>jZLxvkf~63?5`f?2VA zHNt_vKGzk6tplSVfdr*%)IUTU3nYLEraUd9$xYyPP-@0e7rIz;a*rizGC+%h%(lnT zorOBix&c-$fZ??t$J#Ka;1Y%P53rHWKnOvE3!uXB&{**ii z28$)nUw^lU94OZT&X~i%R!=@PDPe+Sy3pYC2kbWiEX7POkfr_F9=~P=8G?=ig{O~@ z86zY!BJ~&%tl?fqZQoX@U>2I8<|nH}bW>d>dSsNxiY6!m+}Y&5PG zEMuw)x1wJGLJgZkSl4nTkFhr?kl7XH&;Q#+$T*e_lzSDn>$&bxB3o5_3Y%iqRfeb&585Tx?yoFF~X8Cw$9f`yii>&JA(guG-C?<_5l*Q9b*;U@#iCsMWBp>gpM2k8kNRCfi}L7hZjJ`t&d*;2 z8T2TK2@i(AX?IcOdjf3QC@oOjpUVb!J_f__x5ZqwDiFP!pyI)3Yl#d)emB>O=iw@c zbg0_*INl8ZZDCox)Rnl^rj$4(uT zlFDz3ET!R>1#&Knu92r)TG~2{<}y%#-G1{eE1G(S@j!apJ;L9T1WtDkZJ_)m)SLa; za?W*%Dq!EXWaX8At}o^sK=s#_rgmDpnI_pgGjy0^)WdYj(N8U7!B6?%_r*Jr>WWQJSks(xc#E z=)g#4-7olf)j%kgLZ0kq*O@+kYjx293$YYNGn~AjSa^yv(Ej+d$j^G!%Cr_CTOib9geN#h?}X8(dxFE}Z-W@Db6~Ee7G3axHAZ4kJe!j zO;d!dPA+XMXBRR{ok2a*0ggJ|i5A))LMX2LRfWPnth4BaA(9!*5O^ER`Yo?8+kmrI zSw>;t)qTiHzaRd66w2#zk$L_b-x8;4Ils@Vg!FWw3pzasU&te`4tFIO?Fb1GkU#h@ z=vJ7C__Ce3g0smwf83hI1#IdtRSfl{31VVvWIHVQHsECXX)Z!nf|Y1xp=@&pJda7b z=6(E7#nFYQ*#ABr4VlimwSRhUZLE+`xl1i1pM9dN##;L3=V!t1DO&-SKdBv_eK@x$ zSvru59-Ibb809|p1gYsCnMEUIT8ZONz6D$Yi^Rj&5bgR|Rj^SRKKB~Zjr26ZVj29c2YotNJU*Ak(m?|_1>dp~ zcz4dmpdYhy1l;llM$O75A3rfShA|sU-Z5k&VZS$Nt@=tX_#)Rw%O-4nLg#yEIK@dyVUl zw`o+>Z>md`Wxf4_@Yt8i!foE5QgsR{Rt>!YF7VJf8Ta5QFi(a`|A&9<`=j9=t%GQ4 z&mYcj$!`N_Y_WbLo<=sPcc*=Xv4^dbcEj7qlTY1IqNUh!nfe1$QOfQNsIk8X07p@c zOQ{KBc?q@44A62qq(7alW>W+g`t59!qsKxWPoV`qVIoa#H!}&ktRChe&H?7>upqNt8D^)y)O5w(f@_klD@a%?a^H#DnE7d;z5z+Ay>a-vSj-9h_8hAVJ_s?0C{@%@3eEK0&EsUplls~ z^T?Qt^@x5oMpo)8i3XycIgt3U_(<7SvmJPfKB=n%-Rvk72o5zv9UZ_V>Z3Z)LkHZH zdJ>3JGuYyZJzQG`ozKqBAjRn;FL#j8yt88t3RvC=#rtjFUxbDNLg z&Yj!o6Ub8TyCYHG+R4N-N&Q=E4^$ggD`uT+_?yO@8B(9+rqHn*BEwJ6RK1zr7hXUK zz~6v7U3Bd04C}^+_0Mar3VYXfZjkjC_~L@+i$hCZe)!3NJvg5^xvveaY9yH@1A=JP z0>@X!+SGa4NRn}~gXKZ17RKlZ4xU03uG*u!a<#h!)=c`7bolflypK#$FR;NLY|HkZ zce`uT?eCb*XxP5|a{mC#!LI>#(ie+^gv1vB0{(8Q`ez1051tO`afM6J)Ou&k5Hx(L z`CUQT6bkOgqHj?f1K;bO{#YO~_t9WdEA~MvGY{vIGu1qkO>!NuFG7K~>6u7z;P0u( zK89xF$wKn4TDbF)Zmf>iEuSk8lkNv>&mbeI131Csx&N;nQcK#(Y8Wq8w0ku!Ye4NyJ z?@TmJl5nwr4+>VTC>{8QJySN_pYH5mWC;0fi5ipxCxQ1J!UcVBs*94w+X}e@KYyH-9L9k~d?K;biY- z=M}&CO)LGj_53oYKF-=b1VlrVjr#?jd3J}wyy!GPdfRouPbuV7LD5M1R$ev%k8Z{^ zcJ)>sSMr2f+ju1P3=OL>Ya|6@8V!@tnP(mgM>uALo-KveV+8XU)gPf~wkL*!Qd`~l z+u26?JR!OHo?ZGjy@q>+Q$Z z@O;Jl1{-9dn)|-fRKzVny@=>cJ2h_L-t*T)ShDd~!`3&CN6%o2;?T_oj#X}Ox21PI zOnvy!biG?hL}srhTa7Rb8c!2U_U8}$z1sPT(DldZQ6_jF+&>|@$P2{D9x6iI7HxoS zxBYAWgaM_1^Q|wtvt?KhSwndo{E^O$;_*wakJ^FwB;p;9+mAtt3CO**9^fw;aT|~@ z>#wOmIMR8!edmAC_0~~UMP2kLTrMqeX{Eax>F#btx>LF&legzTyxE7q4UwIC1MV5UZl;6c@A@w_}wui zuG{rZr_Fb7e&QTkH*}!U#+=?chGBkA)O6D~4?MfBGw&b#I&FLdQPE00o?1r#9E%g)tPv;OF>*Vz$#h*7;4c@ zqT>?P7%X<#3LOL7s1ph?*Ff(;dRrr(c@oOgX$e>!k19yC{bibSWFn}uH9D5fwpy}2 ziyFo*k4SpZ=C#RT7p-ZTO2tMz@ItMl*!Lw_?!Ab(5P5_bEmC2|UoWxzzD5yKI%cbg zXHPJmJ}xeMJzTh)_wow^d=p9)%3o zq_4x7r-oAxU1A=i?$O{NCs8q}Hf(uSFN#$*D0NS(q z9?@v=vaTg%f4#^l#JtN`{plz@bC$s=FEt9}m=~Br$XNpE9L1mf+;MOJMn?MzLjb2e z_RhVnugi+76?D!$l*e!lTE-dIuDDl`8YEE^My#tkg*2BmvAkc&3=v))uXrvyfNsb| zcUoFaDnDL^yrZ?G)s@Vy?YtX<=&i9Fk{;sKsj8hx z0h12tL6JIDBN8vE+pjcZ6iSg#ouS4KoJfT~o4_LL=G~Djr{AgeK zc!K>w>7?3vG{2Hs?;wu%7>-;nWab>Jlx9uKqERmZqr@tA;_&ftiFEw}Bn52`TYstd zJelo{I|sI|CTt0!QggG{h9TleocUvCCdQ~rW})A+n?=%U>05cI4(8i?C}<6 zhx)(t$#H(yM{(Y8~qbO3D$Mu^P+%n|r#CQ^jhpA1CQhbkAE<*`~6*Jrj|n#i8b`dkSQG zyXNjK&0qyg{9ws`nEG^6RAa73(+|9lbntvaD5<2JYXq;O8qH12v%nwaIbCOd*>ir) zj@h}r2Ra)1;d4Ivr5NeHWq@3+-WRqP41(Bayf>+K)KGO}>0{6U`c!wK;UG(;8^-$l z0y)YrOjO&8=&`|0WN1vW{ubTnl($Mz!%6fnAy38q7X9j<2?>84S{EQ()GHiKxi(+RVS`|H3SjYC!~Kbz1R z1mm%SBt(iJ<)LDvOJ^O9WSmY=3A<2(#|{bL+AlQblUimR{HGfGmp!9_gT1hmtWLu& zJqo2)Y7gWozxe;Sw{6Ba3uMSYiBcn~NpDJLMa-tSmT!j?XO~6f#;L_qc#f*8YZH<) zEv3riL!fJ z&82qR$DLSP7xs-z3pmzw(G@0DUxw-qHBsf`kE)q$s+mi?OkN4IBRloJt# zDven!x7rY>@4n2_+VL_O$8!CDJn76bJ7k*-k=Fn7qX_V$9B}06TxNM_+ErK-%u9_C zC#@|Nj=LF@o~~&(myx}~p!TVa>E07J_EB-1UWJAG_)wDISi@8WR_sh+i;Y0!-N})Ye8Vr&v z55h{KmY4^p)sKAO$$|IW#U2Dq%17_#3p%zNRf{T=m0u9U*g-xwefsa=*fH`cc#igL z5O;P0QDmRtpBxw=u2LBK6W_W$fd=p zV>mil+snMmtk!Ng(xa2^-I!4L;7F*_@dIC9@P?CUKb+@)GRLemLm3cCUQ@t8rG8QU z@QvhyUtrAOPb}z-?1GNusX-->%-bijOSq^Y+pkXER_-sH{k!)8$V84phudkbu>`7xYQ&ds1y&Ni}%?pkQJG z3kP~mPT65y!B?O<$iJ8F2t=T-zr|3x8+oKDk^O0BMj0_?RXWa;q+K&r}UALO;&8&GelaMJ=kTWTGnVAEDx`VaDZ zL1k<5G%@rn3|K~q;iUd(72aUl_ptL;U_HN1H z0A$c713w^ceFU1AKbXIU2L3-&2O`sWroOJ!G=17VyajE%9T=`SG)a)QXq6xII`NPl zfC+C3fMwz;RNvfogDGq?+0PYY1_GrW4a^{wnNd?_h_HvwoFM%a606x`{iY~v$;zH4zpm#TIQ ziUXb^yYQL@0idt8(B!Cd4z%xQC%~NL%{sszG9Cm&;Os_3mDtW#~;U?&}FaiT57okU~7ATXP!j$fI-c?SF&l3L_LL zctqKJzj%CjF9F~PYRVHJM?8|D3KjY}LTW{zh^-G)HkPUqg+eBN6$ij@WU)x1QB*V$ zQnra58sxa)V+>Zv=U|3ot9m&~ww7>5^lOq}2m&D{_z_YaZN3H)4h_~<9=b;^f7<3F zs-)<3VPFhz64;BakeRyjoBILM{A;L@nTYvJbWA3eh4gWpc$OilNwmipT8GU}CXrOm1_5*!vHgH$5 z#9ZKN`X~UA_`M+2hreLMt%Ci647DkbjKsTR=v}DBLuyUVF)L0xHis;q&B{AM$_<_ z;Kf0#1lXsi8=XxBRG5Bm#UM@g?wd=OLmE;<{+c-sXYQP#>BKb8+6bBxm4_g7k zaB&%NrwS@R*YeroV!z$SAhFjS&#Z#s4J38sZ|Ho!B#eQU^*K{!0wPX9mMLXB8ann% zo?w|#-JcV=D5Q86Ghb)i!UWw20#+L)i}-8%pniJg&Ur>#1nvSzRL^^$0bzU2jhE8G zk}&3W7i;t;0Kq)%iwY2JliF1G12(!BixQ~{BsE{?o?M~xnsl7$U0hBqewJ;*lfJ-tYUQbi17{n15zjpihh)Z z3&raSxe}kF1tx2dg#N>XOVqJWv4t~QyFt{rO%$eN@AbFD$i|XDzYTeIAURMn+ zpjNa2qqW5(=ip2gX_LnT^XH~BR!Rycj>0YUX!(Q%?KfURFtrg_reV-aU5k%xZc{IY;Xzy(5JK3(E{(G0*SqvCP^^`F(3&-eV_{&;-&PX zg$o9q?z}VQjwHJc0EB>5Q22ktrolN!+&TcUJGTaJ&ks1mpBgqkrAqb+ZiD1VVgZ~G zheb+|SI#N~12%=p{Z4&9&gEZvrpO(Yj?4pLmBJ2-*+B{_XbC>gK}bk#SdWGr>miT;0*g_hk$vxV$ z_b(A_@yG@mqNCh4A+IPb)U<}o-kBIpa06M<*Wmsp4$N$r36J&mArqn28FkKf;3>#N3sXxlgX*q@e#T9(w67Uq zcB9J@7e^T>TZf;$_&zs-n}W`@lpcs^G}*QX+1Ke_t#&A2eWnJlqa$!C_4{91L;M@G zxjZ3?*B78pwZdLmxFrn|~^;EU3f%*Xd{%zVA2Qe zw=8r(zE2A+|3}Wl{Hqfz%_q0|UW}WLgVoMXKv-FG>)d~L5Qc^ixul$&Qv>TRe2qdN zkJ(}VWNGj{h`!x7kUSztW84n_Ec8o8UkDpQ=+%y8 z^QnSQr;Ab>j^Bn}k8^`G-5nqRUJ%3%P?AYWYj4n+2x=@>h{ZnuC)zpF6rj@V3okn{ zp8x*h(Fsb5MPk8J*+j0!I96*YU4lf-&w)SEP{=uGRRr~6rT?h!$3I!91r>xlYMQwfQYN0333QZ5cbfCZ#k9+*snuxPKqtIfvQ}9F?}MCfY^2K{^LNN+H~V#xBfr0 zKfV$)G$J$uh0rYVgm}OXqwxR9)DFG<3SpuWD)8bz5tC_IZw!U7q0(*~ zwz~e3Aq`0H1)4Z*eH@<+$VQ)`F*+VBfrI!AP=zm_loxCLG06%&`*Z&0%aO8aPc7RSId$hcSqpw@Rt{6h!dJYX~09mMKxYP(Hh zxb%6pqS22o0GhdjaDF~VqZv?3XKJOuT+M5n}_GIVdydT;? zFK>xh(tCl!i=}1J4OAztJ#*&JVX1%;@qKXP#OO#&=t7f7S-u3F(CWb8rz5U>2@h^~ zg(7&R4DemXeL1p`f55|%5)%OVS_ine1!}-EbZ?n6Wc-~8hHn%7`}-0cK_TuAZsoU? zT%l~26<*UQOF=-+Yan~m34ow(srn&v@H5BHV!@r#qlf{q|!Djzvcx z?-)w9nS&i`UsNV`eLA}eNSQxJnN+E`B2z)`=8&t*qFMwJj0Mnpbty8EpFe78d$tcY z!y30Hlg{|Z>qc>o^h&M^-zM<+_fLZ>-C8Q5Puw~m*#gK z86TLm8FPb~Z<;D#w>F)@243XOTWZeY|AEo&(WHh)*^&cm;i9Eh`)EruKwbIJ1l>6E zbQQ#xujbtmu20sO?<~9pB&iOdgtXpiOZXkCPJg-Et7S{3N;cb;5eq1D2hs%~>*gqk zKde|JAlb>~R(U~D_KJRr6LGivJblB*;}teN%yYJG)_VSifD6h!st5++L`UE_dz3BPW}19YaL9BkiAroHLtp)nhTa$p^{U@#UVeRRy-y0SG&hegE|9|Ix1 zhgN}hOev!&-w;T`Y~_JpdYVOz+xi--Tc9Bz(J?15|%5GeIt4G^wqh> z@xM$FyvzUlAJUUpnVQE|_t2IU#(Zs-ty+kAQu&%biNComl9#0Y`{J(n)r1t7=`7gp zZa&08P2czgfR9)H*ZJT**7u-iyU)z=lzx9Fe;z8yT~a;-0Z`>$_$RsVy6%6`X>ATP zA8&uE_JHy|D2UjA=lsffdIT#IxZV*$sj-gjz1a~u)hG12Two0olr$H>6;82%lp8An zJ>}Y!q@B4E@fs6WsqOYTWL^QIg&l05Z%{WTQ1hYfK9oKE0l_a=-6w*D*vwc7tC<3P zkBQsBoF)BK7uH5X^x&t(?fudq7I<|G*#FgXZxW(q&7m)NbTJo@2VF_#QiVG?3=cY< zV`%05pxhKCoH2r+;4>wNfbtL=SqgpNzFmhL)_pkmehQmhCOZg|yDt>A$aV6tpvcOpQQ4h@8&&=?CRht0j;6!8Jx9=rqV6jDv}u@&Eq7130)M z(r~@3&rnI@2eX(E7KV1l(<`R;2q!yu{TlzHnokV=6oG8aPth2rgi`YykCv($73%eW ze$Vecw1gM8Qq+488H2^Y1zV41B1Rc{hZs|e?0_&d2!a^zDac@2i9MDPMN%Zs4peun z-)`Kpy-0}`&eXz<5odvWC&=E))(u8Xh8uhn1Svm0{>`oXkr-#?u?82kj?gVwi~gv7 z#sG4<;;#%<-Vn@ONRT=}48x1*!4B^#KrcQcMp}qn+`cy$een|XU*kC;Q1rQhTH){B zNskKYjMKx<8-o5ve}JNk^o6E-h4vd>=&by=f!7qxrCWgLKU!o8Fn4$X;?VkXhzaff zty<`#%MP1waT#yphg8f**<5^@pM(IC`*q5_qj4>0FL}Ib$Ia%yJFpoGCV_F? zMR##}N7@L*=m*tRDVH&~0QTpJ82ODM+2!w%lgxxwDR*uxgf4zA>Ap{^2M=ZdJX)2L z(rH3bp(-@M*xBxpR|3m<7oLtq!$UgyiXA*IS$eE1`nH|XjY!hTR|XzCR9A}aKgpks zF=A3Zjm#4JhULo(sc|7#-jn7h|hBBJ8OkIS!~oLK||!z`N7^{7*{KuSd20w+gqhpFejPS!4(UvUm zq`#vVyG2amiDf@51sB7|4a39?B~sW+uDZ40xeyb+Fk>zOm*a#36-a}8)x=&99NdL~ zl|x(p{)%r7!if}KKhsNlS+(Kw_^6%t;^!*Ii$^livcz4LHFse8zEZVT4lk%8$dmjg0?UagW1RI2` zmTy*cM#(lYdRk5Ojz>)HYzV5vP38G;OrLliWe}7R$mrloe-M&j+bu>o>B0@MkwZ8s zjebXgRdRpn8vqKQO9Q?npHwRmtY8JTiC@ha)_uxR!IH6ns>>lclva4wF=A1y?fPuv z#BJv!IPl^8&jZQ)T9@GJr6X41&trSAhCn)-J<>$hlu5g5N4rfTr)xH!3!m{* zxLP3X9}&>)s-WtOg5~#TV%id7_yE2Jy5&EyFc7SS8jc zyJzqm;}xmWJzy<<_#20_M)&04`)OW{7{2}efX5~4cQQi^Fe0>`?E!|O9RT;PHUlrnm8&t_`%+VQCIH0xvT5}+KVXOE z1+lasEK>jJDJZ==Th~Lr)HaTBD4kycFh9o>=xeT;`AmERa8zg;u$dw?k99}DzR`i( zraJX~i*TZbd&?aIiM(4cfKb&IfHw3hmCr}LN2h_|5Nr=sg45Vq@r-&}cRpNf;i_DY z@R)aG2AiCNOuwx-^hS*Qgy)W*&@WCe)i3S}?RUj}cc5TNN%d#}pe!PFE5hn+GFiy! zOMO_WSa*5;qzdx_IbBUfjj*CvFpH05WCgJnI6aaL(d~jkk9Y-Y82G&hmBY)|6e=k+ z`@oJ_^&H4GwdXnHSG|7f=e5Vs^DGc>*jGSHWJAsfFt%2K3J_*1z|zU_66UW;>1V-t z%S_0YiL4q^`vYOY5LfOwpoIz_iBY!$!_!ru-1-$Fi$SFxG&rIyC<@Idc5 z0=PkC0SU__0N@YFce*mU3LmpOlEr)*vH2KHmNVJVPH)n|vtN0VOpSQ$q1Auy-rl1I!_@hmWq-z;)7a>@%BFI+p2ml}``~=*f{XtRt_jVuLKE!DBhuRu{!A5*9?UJoz<^%j`+rcQ?+^;pA z$4x9&RcZNjo)AO=Q4%K=ev<$WOq&PP{X5IH0{Bk~)TOxYVsCbu;3Z)=ZEWkkDF+Xc7V97 z5T5+7Qk9%%RXr8LaHzb^u*{`VeP5Ne;Rb{^0EIeDP#?)EqErZs4p{E1>Um zgFcx^`@y{i<@IdBs6kwW<#<(AG%?b!HUZE9lK>G3nZ;p||1r-7*C)x#9{=TO_!mG$ zMPieVfy(_S@Pe~&ZLv3>9L4wfeAL&s^Y`!rFx2jPL9+dzJJP{iK{nd} z+<9XPpowdG1SaoJ3YEP6BmJZEb1g4mwyg|%<*746n)LuZAPPa$b zK=%qry8g9nJ?Pl$0K%s88PaNQ4C}xr?you@t<+7*k9r<#8` z>8097!%|lgDlaeKUk6;tT6=f{HIpwNRuqIsYf~9x|4z0CCTr+;@UKE z#m-J9QTY1qkG|KdAb{YnyO10J+sbwzK05c|XTxzW=LHwlWx3ViV&RHtJry3Ze|>0oighSs%+rZsIjc^i=DgCps+ zrD!Q~ZcTOtdUqEcz=CAsONBcLv3Anp;`!nFdME*^7w9ivC>75#*Ch6EsU2_?CjFE* z%p^mW;*rqS55V&>;F(lM;e2TR^%B4|n3|W%GXmw6EL!OEz z5Nu1&qWx-D&IXHK0RH#58)!Bh@P__Llu^XWX?7IsB0IL|*oeTra!7Y9NH(1bviKc}?KxCvCL0;ybIg#zD29 zR?|6640_nsw>O~x!sr?oj*WhL&|V2ORJzXa7OecjE#l|+Vl}{9Ui|j^bBP0|&YUy! zL_PczHisvGlhAtgN*eqY^%jddx~uAH6!=um^a~Ji zHQs(8(+5O9l5@Z(yHFVBDphd_p^w|809C`T@-d3kPa#T=5ezbJ)fa%xS}{SA?NVBn z@Ln~UuFovnfJpcNFn&u50Gjc>9FtXyE4Qo7SW*uMqF9UUu`T9)l&_m&nODpNL-K#0 zCXIw?Zbd(jm>eAkAwlGYBn$01V`ScM;qNldTs~Y6-`*d|B5OxT3_I*xPpL9|N`g4_2m}LV0+GO!2Nu>r zWPrl-Mrd14-kVuy=$HSi-Gs2LUOHweN7X7Abr&Zk{#ZgkpxzrrEI1Sin?@`8d=BKp zn~ejOh>oCMi~TPUbI)# zDo!|vkNJnXG}B!;=nsPbGhOWh@e6hrGFPB;sctyOaH z2L`mu7nU5w;PR>q5461jsx)RUUjB<%J|>auOn}#?t!m6xm1A(vVy1A+iWyZ5wV{8! zkX)1rg9($2`}1Ht-hKf(q9Eks?}oLWBr=y2zC0UsN!};R_OCvvao5=uu36FdsXcdF z^dj!N#A3jCR0tR)%V|HtZ-KAyc*dPntz1+eqGpgGJWa<;AK=Q|LgK?VwN;Lzydt8) zH8%#ZU3H)L1xLb{!Enu$8hL@O&8*eCBzvMULRO1Z@{yQQROM9KRKkiRI>xUt`u*pp zfe?a;qodzxmC$E^r|HTS?-e;mc7k`OmvX!U&|Ny+mN$9v{&s6J#Lcja-WWF1qD-+t)2OKR0dc`*fwh*`#B$8ovhSe8i;3Wb z)5WdHakhwkji8HIbVA2;(rsVe#I}FZSG#yrSsy&d`%_L{uLoH29sh#{GWv#iKk zYUzL-^$^S5bjM-y2o>+XD>oxY?8wfoQDT<9=WLX~#E<`R0s4bDxs_Aquk=&rq~uG^ z5KsHopym&U9D@}HHS(OHhc_iI4+(_1XQwjeb zY?Kc)7y`YcQNopv%SK-)9^cirD~mw#Ymn|%>L83Z2!5d68?1=p-{=N>*v}uFda`6^ z%_2z&f^mkq1;ps5Md!ANSpsz(W|pJxa*z<$c+zd-^bQECZ#KXcc2R6sPHGlK3ksEw z2PV)WzHJIx?ogE`mw6Eos|%}?0?acc_q-xmg*mGaWOr3e&GY27yyZ2#KtCv2y5QZX z`fQ@geltZJbA?hD*NePQKLnRlmmfSlD^P}&>e&gEeh10;X{;&zkwZ)pg*dS&OoMNwMYK)?Goxv6fJL9dpOqHfWrb=bs zzKWcAqF=Dnn`%VWO!(+InkN2JBN2{3t64VNRVQy7!b#v#YOm69pEXE=k&ov=&T$E6D2{clViR%t!LZrA7_{ zZ*p!og;5Ae{DyHnWK+c+kJ?hwH|gTECN`pDc;(7+@ncv=u(_^gM#m@HFGl125mWoF z_~K^KA%2$p;|FdQ9bcL#d*v$R18x^!8BJy+R+oZsRGzU*lk~cf!_RLCTcxE=QRj$( zj$Kob**OJUPw+Sfv&SGugM__?2VlhKnj!1pq{Iy(AU)Ou^|UJ!o(5Fz%s()0cp~TD z$FLltV%f`G6d>6qzqK`RNaC~bPj&#fO}&5m&iH`nlxz$AMOcJ;d|fyVNp0++q~!2U zT$kyzKj;f~3cruP2ycri7$ZSGK9Nev&K9+ zmvO)!V%Atw-JFy(=4nug?7fF7scgSI*fs(*^&rz=Y1kmc0A&t zd}3a%1U_qfGp}F{IB}d{6I=^oo=_@ZW{x;LAA(xYVN&!iQm7_*2YYLX!@h17PDC2S3z+cKA23- z=aA@n+#ii61CK+m`zoO=DVF!LME7e9+&Rkc&Vl8?_l73{^a?gdFG~WN;#pbn6ImC$ zwj%PlqX)?z@!Gu0l{Ct;dP(Fr+4$kr`j>bvB%I|h$?~vB0Xj7fz#!L z!#Y;-{dU}5Y-Tva$g&E?4a+MytNs8l4DCojet6~8&jDPKw@$_T`A(WNK7M15MevBV zf$j%95ha3N=Q|O%*2yC8=v;lp8VXAWP7*TENuZK zQEvti#|eR9KSUay;|%h;NSaKitAK=q+;jmPM6SVnZ`9)g=W#fVT})4d!;W=^q>H@f zgXUkho$K;XHj~^qe~#3@0nGuN#~msF*>Of#NyRpQbrg$UEdGglaqm&{c1~p70V%9D zQuZa2&ciG^Z7EOlQj(_;`k!(+OD#2` z9}t310d+#~M8Lc{)_o!9oqO1Tbbf57u|oy2BTwCncuvx2BYC)$VHGvZDuvThv`A;) zWYR+;S@jr6KC!G`aaR5=V4=DN08uTwA%<8)amEt?U#1QEPzx5+EDTJf&f}u}!jbs!7=%7;iYXPB)g7e+y^b()0N# zh>4DD|Nfwwo<;;O)7Hk;lR~selg8D~=fJ`rmyCnng_Mzr%vg*rDd>ll^o-}D0bmM= z4T^Ib<71@rXQo8NYhsw#s_x_9>e*+yO=l`}AYZ%=XE%!|RiiPJ1qFy{F_{EUuKT7| zPAIcnyBdd_nTXBzDv}ggA%3RcNKjU8f90)fo>3pft&|WTjI*Hw9*9Oh3;%E(n4zw(g#T8 zq3ehadX(`P$3iCVy<&`F;{y|VdK9^M)Er zibg3S*5?<`#<^PyzkmW@6(~joU-h*0`M3ESHAd|SP1_L)$u);5Z>1|md2y5^B$%g1 zTZ`c>iKe4w`R)#8ix$3)+}Qto4n|127dc$KrR07m92WY4fj{X|la`tZ#g$c3@Vy z+vxy&n#a_%03(=*?^`Mse8v=%n`_@KkA1BmN|DvhN;G?`<9bK$3HIyf5u<|qfC2Is z&%8FVe9!)QCHkMbcV-|@O7_=S1*cjiZjitbZABOkakhNKS(sK)wo0E9zJS$pZiCKRq(Wc z&PS~>sq5#wWhi7|Fs!u@Y|-WF+wV39d(|d9vep846;IKn3vIeBj*%^^AbV_Q30#Cj zBUWn<3TK}+e*2Y?aiw0-s#74ywqk@=VrIHz9ZS6ez{YJd6DRuO)zk@A#TL>L=gfnU z>r1hb=V0=o9Wpc92foE_3-v6X@>*Q5IL-w2mD8MLHM7k;OQ^dK@V+naK1IF#NnPwaT8{M~HKboK%nzmaVZU7uLH{#K9ddS0^+CzqT0K8e$T@5tdVO}&KG=cvF&+7-Z*+vmPDw_NXSwaD5BL3Z zz`}HD1+r=4E2ce|s~9W2|CCxld73vI@Aq6@s_RQ{{L}usKwk!eclu0%mYpjDT?j{H zJ!L}}`DXYU8srWDO1ipdM0HpBJF%N<*RP>9B6M6Hd_=k@{y4FSa?%n+8RGBFia(=t zNeA48@r)$r<5J2Z08oUiuv<<1eI7(7z`pZ=s)+y54rcTpkKTCtr%uI0EP*pelYO~j zz0V+4&GiYoG@|w+aUAP5>(~DCkw-ssqt?T{_HcYs`qx0U+F@0S8TjJ_fOuxH_|*Cf zI<ZZFD=-+12yizQ0cBD19Zp&q$d^P< zlYHO_;Q!0^2_LirNlv4HXm0k>GMw{h>{8$uwCsVTGqQO0OX&ms&A|E!Vs7nCH11 zipf2fcH;#@Bq3iXS*|Mz+>a;G&Zner0Uo{o-t3)m?3G%2K^vp%Wq*`03F}scEK)W* z411x8%-pjVJp_;W2D`Drf)4FE#%x16PUMvCW|+brj)p|fl}q*HHGJ@Y!bKT^pG5nK z@04441J>l_uabIc1&4+;Wv>Xc@Q*Nw#*;L{N_`Op{}@wqXuao5U5CH>?HgMOtFq;zDJK$q~4TJDMU1cC#Fjdp1v@k z&tw;_B_U}9xZ3)J%0K@qugdQF8D1LIi3*eMqBLHh{vX#X=C zG}J1hHCO&~y&%0Sz%U_r>)S|H;(1(CviPM+y7C3vtKw(J@wcPH&(8E}#LAJUFNoeP z;-*m56|hZ9qDc}M>h2mlrlOM*%wuI9*Sma+!X`F@>Z@oJI2+S37zFw8l`{8?;cUr) z{qoMQq^1Tdtx{Q@S9B+#p0d9jv>T+4PXImj*hMK9*~?s!+dWHm-bB-ckD0getbk-* zDvljzkI?%_ge+FA(VM&Shn4CJ*O8M4pq;pl4G0T3EP(-`CtL(nqMrHUf!}}K*`Og( zIreNAT-_A=PCZ$Xa_dDx0jG8QGt_9@qV!E zw^u1=VZRsao5a4Yb^|2s?}YfFU6XD?M!|Ohb&G#M+Q+Rwt#^4gyI-0@99oM<))`4H zzxr@_fBKOW+1FGrl`vBBG+NoYl%*YxjI>!hkNy`&i#1onepuIVRImb2#YbU`o+^z zt;=YOF~Q_=8T8eA8lh`?M!DsK8}aWdg+AmGPPKp%5b98leq-U_?Z@!y(@2;=2j1s& zy!v3H(Mn)%*vHBD;l^nZ^GXV96gGQu^BQx7B}G~L3?`Nu#UVH@W%6d| z#Vs-*+wD!qj)>m7DCj=4aR`h1ceg8d_|7XHx3=gnI>lc!I!#0I@ zw{0=lqG#NH?n4koG|9&bRI?lZD8_%kb-lCX3+eL!1h4VScQ<@Q+i(#wEl@y@w8#0PuJnlPji{#JYAZ z`C(wbV?$y~7VPhQdf9eWwoEC6 ze%2Z^%bJu5_{^T)qp#k<^y23p-Zk*CMTVv-d~{Y78xa^v51f>9&ZW}qqs8T3Bi#%n z9}<0zj5lG8R-6ZXG$SHXf?Dr`2^idq*R1 z@7ZMY>M=y;uvMbECIrwo)%zrPC?>xUC<&7_^Tea1ecEdqY?IAg7*rqF*DO(YL?ri8 zA+O9+y@v(w zbF=-EvQyaB4EK<7KZ2YI_o=X?o3OOAbF9vx2rzF*f^^{VP+DOjl%_ z-#h5~82VH>IjUKdk?OOe?Q2w)jj7PsXL>Ll*{eSm5n@_E#S!+D-quM? zx`#s3n6m)`FC)e9ZJJt5|3|-Z-QmB{4GOmjz{C8a0R54EaRPH7T@FrQcQs*V=jSX9 zmyoKFAJX(wCQt_36X1iBG#)va5=X?&=GmpXNVVvIQ{ERL5OX`M<|j&~bYEEMWdldR zANdF?ZjitHKxHz=Bvq=N&mVlPv1qp1oa+wHnv)$ zP2flXNyl%)jV%2Kq#zMa+*NqN%M*vR?&fQ)r?LNZL}j(9l*B!v<%7-IYxOsX%=`UW#Eu^bVVFi00J+b5sgJ|dCy1Uuw8Gp-0uYuoT3FjzBp^0spP3#ZQifY=!oZ4NPN)MA?O$F_5H#rS~|40 zm~Pvu@slJ!Lc8bGsnaa6x;4%$GPh05$H4gFb2{donPuir>J%(Vz;nxxuPslY4j~Y2 z1@m$sQyP(rAAjy(mrtlg=FjRL!sqUMY&0ZV(^x-N78;#If0zu4{7=NHJFx>u>u0%7 zyDE2ZuQ4&_edaBO!u=>8S#lXAoet#3Iu7!UQTS^N7e#r^1ejh=AI@$&ujGCXe6O!r z6hsiV4CvMnGYjVq2`fn|jYBu3%JE${kx=ixNUYWRiK0a6q^KRk(W7hV{p0*hFEQLcpN$F=(ZF1v}1;VxWlC+tFq56krQ?8^NsI zoKb(daXTb4Xy~Qacf0I$s|Z&rYai^%T^y#8A}+I%K;=?c89N0EU6(k&?p`;9^KcOf<{nduSHX& zvsR#Y&h=N~^1U%nJ^#C;jONK+`~v@ZMzdzntYyyljwgVc-X}ck>`fj)JV0@H>^Y=y zv%P_{Mfx7|4%aw|A*aJPC!S@*`)TPfLesgD4i7Wu+$mUg=m!c>WwtR~@G%{XLgk*6 zSrcVtG$cKzy;YE&_c`U;wLf5H{eQ(2x z2R(GRz&W&(gp_oLlyr%-v~&n69iq}5BGM%(h=_Cvs5FR5i4rO)hzQ@@-g|%F{~d$j zxOzEf@4fa~bImp96Tcp#)10Aa7OG4z$UMnwvfzOq+G))hlXi_D*@9BfGR<{9KrneL zydj>F;L_la6>^(e>C)HQ!v`N1(WEMH4;y(+LOc9BaPi^sw6v6V`3 z+p00#mvmKKqAI+#!!1HzM*DdB?Up2pBHLL1AYfo8HkqpDj0-#EtA-)Dz)b(W1Xd_; z^G}s`N+ByuYjzCe{@+AQmNFvyVU%|hU(nat&_od<7C^mpZ@|zga~h@JWZ$`T zlh+e#{MOuq>a(;9HHX85oexyIIXxbJ0f;3@{Cabx58R(nq={z(KRKe zUJ@6Qt z44X(DnUME=&nPVGT){@39AOPzU9!C>l`Dp~S+GPrM=wK?W)NF4X`vWO+d&lOQZVIJ z5JvUz1H&IlUdFvT&v27k@&^O98YTxaq6QhiqRzBmrBTA)I)#bQtgR!&x)$*2lME7P zOIL<+ISdZ3BS`o5=437r!>Lq~xQ$;jPRxTDL`f>|f=jse zEoiWMhF~0=C=}vcO#NLMBj!5xB8WnJ4m)pg%}zD6jTIMBuV|BL-v18^;BQy-hSVab z(l*m>@@}(u&36Uj`ZkV%dr~Uxk$myn+sn{R9U_p5>`#2X_k^@#{q}>Rauwo93SuL! z)*Y;;;dXRLPr~8{n_KqBg(*r-Xvg8HBVe}Vlm5H*EY;4rcs_7j5s&5P;JPuos`^~$ z{VJX;&+USA4s)Zs(`ch@He#>XF;+?Tf>*BmGo_2grx$D)r28+5`aJt}KY3yi8*xTH zO_F-p?=B46T(yo#CK>Jc;&)0R=8a2v&&}5G9Q7pqgswek89VH)e>Co}tJF$*zpgsA zTEyh^=8)p9RawMqI&q49lmd-04v%M@!l3QD7(*Lz9_zI8jR!K&xZrECEE9$1ODLOD zeyo1CWV+90LT9sV`7%Z5Kr&~L4I|H08_lvyOaQ@VxH-gDi!hF$8KM^^q!OL%HJ9iU zW*F}z<(BO_TVsa#Ahe^( z!xf9070VL|Vkqt&FFXPk3)R>U$;$1SJZ6?tevpU0Azu}cgOW9+_qfvDBbWXB@Zk{f^cHNHY6m!WNJ39W@i~UN6|fxW+CYOvvi>r! z#Pz+{12Mbsj>sDCFC$rIzDgmrnBPQBHL=(1Y6Fs#Z2q)Yg__6&O78*Y!L;uxe~S}P z7!->ckc-p6#n&TSXQ^-=M8d`6Q}TQ1jn#Qjt==zv9S0r0MpmkoE zwDe(bdCUP5=qcWivl9A}6f(xMN+L(P6=xLkgAsVP<8AJ{j)sci|6J-V<$!+ZyRf&| za7H}N1NC|PBmvU;66ixvIXTVf`f5kUr?1;+vWjO!-xJl<59{QPJ`VEiSBS zYQ6wm@$Y8i?ic0ugWf{9KLOYD0Zcfm0etP&d6N`=##$Cx=mKTlVi`@FnTrFW_!`s3i5JgLbH4@TY9BwHBI<))de1{CzA#i6`+m5!c z{P?LX#k=SLg6r+(!%~~=XCAt!SA)n1fhOl3($13xc8}ZZFjWgawMR(x_?%_*@?#>Q zFw+gCYCMimKu)d)3;4}ifF9bMQ%Ua1`+2&h-w0*+#t*i<^u1qzzVk);Q3zN%zE5r8 z_%;8FA-;yU3dBk0{Q3I%56^_6@Sd%eSG1I}>j>WFG@qxtk+U!&^V{{)O55-6>m#x! z!H*<1p}4n|X^AaFfVhaJBE%S*$y`vz;J!91Hc?5Rf5MSsFCz-)^$ERLqP5G zqo8CLHkKHglTZpB*|#m|d?}s(NlqzZ(O%Nk#9wpD_sWP%D+VkuumXf=rYX51!09Gb zqlIu0r5FAjJ#a=|0C2zl05*96W_!&DwwHoOY|bN`Q|Ei@jvqlb1l!FdYjU-TsrE4SD zDNqDcTVl64$2j*D$ZsEQ^&Q_`q4xu;S<1P606kCHqD@8m&U-f_jQiyOQ>Bt&BJC#n zHgA^3#-n8Lva)6{CydYcg<4)3y}PdwI^{k@3lh|uvIDA$e+JKkC0h}23Hs~W18F}3 z5&RoHO`??jL+Whpe$x8jSn>-X(o(J@Q`GZzm^t)N8T)j>2A6%b~14pZQz*h&k1lVAvc# z3^Ge&iBge2bJsDkTn<$}fMgF!azLQEUvj)3k`!o$%1N%3K9RykvKu5-cIyr5=j02O z*pGeWPbzVWHe#eebRK~5qM@s7ZEUZQFG!YAZb3-Q8(1B?E}zRA2>j=aF?BuTQ>P*3 zhjaZY)bF;oAAxm=6^(h}aE4<|XCA2m6Y(@vDX zzYVPQrr0yjBlgJtJeFZC;!Pv@e@@=rlwo!SjB{Nzlq`9qp(WUk&I5(Zo@#ML`aeFt zq_9Vh-YLHX#^?R2eu#l{M@-Wo#tWm+VG5?FZCo)~P3DU-Q=A=gdq}%R~Bg zFD`3=5AQJOAm!y?4}?rhJpP2~b`-@OdUkYv!%I51p3`t@D8aCsmgS)?K-pl@O}*oA zw@&-!0$Of)(;d#|>dvmSSNge1^=Cw~zfoauOQGjAW7EkbQ6zGQZ&-xdpbQl3R-8?AnXGft{1$2^0zB30x?_wyym0~`eT`)Z6S)rD75AYGLHA@W z(Ji@`K>n$Q_WAKXRLS1FFj=6EoFMdFXqf;;{mILozCbW73ifcA{UW*eeLn3hR;iUK zhVF1!IBwz%=c8b~B=-2{G1iO?pltR#WHLc4+wECqmqLus=FPTW#V3qmcw(302ErxJ zKN2?`co@}4E}w&~ae(gXnilOb>=2}9fB>Hm_5>q~^g^ zdTf0B`pNoT84bbt7%Cn(8k+pxU7xy{#iW=;x`_aA9e>OEE*y`8@6tJ}UDmJ#4QTp!vl9V&bLz9Iy6ZtjqBZlE`^yd`BLS*hbX z1x`a{`_|Prux{)n5;>>H2x}}ODKqU1`_FLfb>_eItB9nclkJ}i#W8cXb{9?uS(8tx zW|3l?PbYQ~^*vw+jm~R`jd~ay8-}?g1{hiB|WGa!1DL#zL*ukCQoU@kl1 z@FNAC`5=v)N@~iiQ`6KJ%Pi=8?|udX-*uq3KOuEgL3v%--b`8pgzo->UR8QwV<9T5 zS@ZbL*YU|r+A5V+&#q8MM^c;hpCew5yfl)7gMUWW zI92{CS(0^I>3k>SJ*sdvl1+0chvxe3t#n>j&DGMh98;6jS$=%J4#Iet0|gcB2DgCK z=m8{WWQtmY)*CMwF#TQz!1ni^aaCOAnmsLb zx}5DHlvm3=C@(NT)pW|gLa+cIKwxY!rZ1ddX_q~Nf-E-mLe!*i%!5Q1jKay91VO# za2E*U4UhHc_ZVg6Eg57aKtaoEs>FHtvBH=8)f71D|1cv@zaGCyUnabll6qg~yv3$F zrMm8$M33*WoOzpq@o#C~UVm3MhJTI@xEOI$@-f3tlCA?2@{7MKTPA5gY$&XO9t<{P zv!D>+bQs-pnvQaaCi9ff0qFWHM1L%|hooUU@%SpCNwfClRkjleaF@6(Enn_%^K|`I zFT;z!97)*LKALe3p(?A$@kSS8=C8!$F>UkNAAqW`kKm&2 zQ>MHEo2olqZwNAnWtQIo!0XGHDT}ZYDK2|C_{Sfgpg0R}&Qtf2;9St$PEet=IM}?4 z?<9&f0)aw?6R}VnY!z2Sk1qwM_AWKY{nKuGm{Nh)#TIvdeYPYP9@9>m7=2P~t;oF8 zOZDilQhYp>ZAh$O2gR0{7{P_$UF>MPfcr*A<`24yyd6m^BpOa;pK9A`U8!IQij51N zP1_LYY_sissNux03{v=#PLpjEER!l>K3Q`UC1#X->00rIBPZyHx!<<2jF_T2RLhA$ z$cW}&wpyo~$xcE-@^5%DmvwQIBC!X+;u{;ABKvM%wSibnJjvQ z$RoxRbP!^rn~4JvW$WLwFZ^%nJp2ZHh_M8z`Lp~DwodYRZ=>-pUL-igJuT0HK70pM zHs)p$oQLya3F1hGMUp>VbcIIeP=MdWEYTWggZ6~Y6nl(mAFaU>pt_BHszb<1u8hlb z#De_)yJU03H-m&wZ3R8sLmov)?`f+us1FU|l{dge&7Ix{_0$<#ZDz-4&+v@FHA!!x z4eTL$TJ1L&Df;r7w)^i=Bs<4+NkP!z3=|S`@?57t@rp;sGOS2BgZQLD>=3Q^>?Xd*~T3q41cat8}V4us%aX7x9^pO>5e)AmMUXwN3`n7;&})nw;1AAUEWB z4<)Y}CaT7$PMq7MEkVnAfIWS8S&cmLw0bBz$ugll9@guC!G&(f5zFD>%Suf$DQq?9 zK(24T+!q!*t(3rP@>@=2>#kaeM~GBc{012*X<8KJQ8P6GOaEDm*3z!gux+vF>9c7m z1-t3_caFMe&v}Kf^D3Unwmb}#WTd{(T*p43!4b{t>fv%GyZO1o1}mB!eff^U;XBn8 zTIR)Rx%0@GcdYs4%rxt(L~u=x-ueUFXuaRWWKo8+-vfrU&~z(7kC#yIx`Y#ys51y? zBRFl-n!X_A$qf!Zm)luF_JfzGEi2EdY+G$n-Dz8{HXL#;b8(49vLraqyPLBF4l3*J z16M&;7=qRmp|c1Zik=>kk*hnD3m_Gz5u@W(tg-1}IUPqb=RGZ6kB!dHw|d<9DM9K0 z?VUv&N_I@lbH37KXq#1I+irsHqg?cdw3@<&n|8hQXmULN2Q~ysr|gtYj{m&eBVe{D zOo}0_Oz!VidR04V%}Nq_rbF0kSxrZKQ<7gUK@{}XE1UGNtYOb}Gw*+B@!et2uOw=} zIA`2N9SnSs>1zX0twARLJEgK1sV43COSoVJ0ghr3-Rey(9))O)`Dd^ zo6XG|h{5HJx+0h+b#<{z^ssxZhF3e`QvX?X{g~gl3~p+479*Wy7YAG;*$I5D$|z}) z`xd{G>Vx|r58YfG#wUi%?z>I%RcY8XK6;(Ox!){I%4E`%v8P6RvwkGD>*7cf=fmaN zHr1_2IeFr+ABj=k2$L#;Ax+NYvw+IH)#=pQXU^TQr5212AspGfII7;(C+>c zO4;e_3MsivF&VYgyjo>3KsgKjU`Y}8?lCHa`~cE{>FxNWGie3mHUg1-lwKspaxpTa zZ8qvj|I9!K&AjHl0kl{zdY`v`#HLO83+NU{-JKF~I|sp6l>B4K*}_A)7+)$_+>k4f zwUh_ zZNs!p+%La^9yFCjBjy(R-W9_0F?5yT(=ikc>Ft963C*<{j^H7?{aBk<+X1rlXYGTo zY%_bXG3UHNI55axR4qjO$m2S`xqz}*sncDG@aX*B zBQ_TrYP0ShIxrTESMO?;Z?k6XI=~Q63z#%wf^sT{;&@$Ss**2NcVA>tA*~~|%QVpf zV~lc=?)&fQ3JJaWoHjh8dF+nma5(mI{o1p)I8?|cwT2=q+k~~RKJQ%Bs+B9arlus& zuwh1Os=j0%|D`K07J%Nu>M-w}K>TXkh;Jc7P~F$Yl%nn7WvnE+lwbgLRR|P2MNN72sZQn#KZX77-Lr>m zQf4R39&d?W^u1j>OU=beZWC*{4U^Da%x^0Bu+?O$xti&>^|eh6Y1E(2iixRF)nD#x zIg`}2c#14ILli60oVH<|z-N7gN&YIfZ6!_l;5o$~$=1*!CiHoWG_HP)M|7;m(R+kT z^46{%vf)Y{1?=iZ)qJSzLeHKFk}y(Z5jAQXYC20)feGgc&#o)kzK%R|@)I)B**`bdnWbQj@3 z(Nl+(Cre=zZ+WVb#t@*<_s9s2y7!`qXwq00I;H(?Q!X@LCZNOR4Xvqr%vX8y9-rUc z=8HX(R|oeJ=z(WW5umiiQ^fcp`X{D%NSbJuRtBx=PWWiD@isES`Q|v>qwPN7fJZ#LsZTzse86j^7xI~A?wpGABor&j9j>1gQ* z8x!@Ma{1W!&$kbP-lt5nvo6|z6q##O8`cvQ<;{2WePbsOktV)4_}VnaTfP<`tSt8d zdj7MZ_kk;OAb9$YA^n-ty$_~UfIt2CO{;xv0KMX2Z=%rCH>!Wj6c2&GH{CyFvF)M(_EWaX>M+1(({S zos$*w{R3c6*FKcI0nE~G`| z3(~PSBbTWYSfRS-pY6z*7f|p5N(e812jtmSMA~y^vmVf_eb>IPv4WFnY7A+kQ&bQ6 z{SBz5W-etK=~&<-s^pLaX4j{t0W-Xa%<#5Cz67HAl(STBi5FUqK}21EC!}JYDvI;B zgmC(DvS9Ku)_x1*MGb{{$og|qjm!paR5gHn!mESfKTz&n7M=6xs@rTl#Gb zx~B;!X8#II%-neNje<`JFS3rFf5%~&mGuH@oZh8!!G-nC-{kotsQxkw3p{1#mb{ys znQ|w`Z`LW(MzNh2Gz`B3gD;Lf(8w~-z6lf-Z#?A8WKCWZ#3@buqR5e;rI~Yhj*&X-$ZBZC{8{=$$woq zt!{uB^iiLF0WHI=G`W<*!^CW&6HssXjKQls0<`E}HDb_~EV+_ld#^kQ0;M}tF8x6X zSvz~9U$tWqv5)zQGD>PqV4kuJs`^2I>rw>T@j>KkfHL<7dFQs1lN#%;^JzTrxkrd` z92^;UavtC<4|w)5eo^P1<)=(H8*BsN>}F66nehGb@q<>5_&Z;)hsy;^^E*-p{AQ5! zttexc@H{hAwl8f5$8@<}#$?Yko9$#R3-d0v**6xpFyi6F~xUwK&9mSsLUZ^5(=5;dNV_ zTAX*ApqSANOTB{+gftO-4u3>twn^r3H6nQGWe=>8{fM_9SN=VgMJ*PQNZI@T;XTD= z3t2D$Zvu1h-$9t{<3B&{HrkVK z-d?6bgPi97Pz>O787sM3V9q7ZC6ihA0&&@7L%87I9f!Er5 zT45!8enkjn_b>q9aswe^F@>cio2@-1luNnx)_|t)64XO9JbtYb$((vCNRrE5!%_mGR z``W^-I&ld;M45;P4+(@fdB`*E^7AS!u8H~cp-UraET>-9c8DNsKoUlYy3V>zRus1hwIVc3ZcMaJ<4vL=Ltp5=430<_6tw8s!Zv`0nqtq<-oLuYZ+FF3D$JoCiKnCy!L<`3AUAYteE&YI)7c{G)RIU*C4{ z5Vkf43Q{-{_e8-U_gtZ8c1a=pUc{6_PsyH=wy92xe|0pLv~4-#pg_*^mI~uJMxO*( zCt=(n?Fh5asQf$nT700}{7;3bA^AW>V$Ut=*Ap27CS-h5e>m{1hCTn@U$QBINx$SUy7mZVyHH8H7JJ?<#I1vLSAt ztb3Zeh$Wlh2x4_PiL+HAe)6Wf^;!KU_Yboc#Yt;oNzsaz$_$TH|HA^T9fP~V(r*c{ zW;__Ww#z6{zZRw0@r_sAk2TPhG4GO-o=xs~ltK-b;ou2pf#l*dYWB;RS7>6!p1Cl( zFQ$GBoQDG)H^h(i<_wzJRIjb`J|jsph`fJ;-qeoG?8!*<8XwuOa#NQ(ZM}*hMBd5* zXYOR*(VkWE5@Wxx2(Ruknqn|IJFr?Dn1nO;pMkS0&$*Z=CBMxp)5;8MNS1Y|z7NhT zJ5%qR!bq9^HCEU1oSGM2s1z2q81u&oqT`<}cOum&bt1 z6a1U>YSFlsha;NSqw{hl=+f!;gk8Ao~Zap2%`gCAh z%7hLz!~8oSv5LF9gO_{aBvd z94^J(bXG)PVnOB-EXm5f0qsSG)$t~>FZb=L`H|hX;{EF2WS;sqisnFEu=$iJ@a7S* zWsAOtj4yvv7!4-~cB^1lh>TvFT>JzrX&HWkLc+AZ?i+Z?Qq41!0RDEHN$vdR9TL?; zkoKmz#rCvf@LvbDn@7nohd8rpS3#imC%Dq86EEm#eCQ8NWxHMYbn+?U5x~65J`uY< z(VxgF{rrrlqQzsx&0;+~>h$(iPWIS?Fh@lC+KWfBHX7~m5(31pkkN$O-L{>72yHG_ zzXj-~#mw8p*sDr&oG}?l#mG95>B~JTCLNrss>0>(sIf#I%0n%(Z+1>=nm=|Nz8QJd zh&fX3*WZ(IcD#4=JUio0#lFg2h!!4*i(+~FEi7AnW@T~iIOY@hysS@Jcx(Mw?0JoM z;$`XJR6_T;tDGJb30YuDA@fE>YR_%Nw8%0w965`7wHT}i!AVFwv{TR@Ls@WFbt)aY zFr$4LwF;o%+b0pjlAU6DLvFLix^Fb{L2J(*mV=~)aB5MM+KuGexpYSF=spo97YETc z^}VI2o+#$^ERS-ZUDp0{-VZph7-D@XSjlYA>y$S5AO~lf=UA{Q=5E-pd`*3uypTT3 zarf&xHxtuh0Ux!^g%A&D73Xb+(009iaQGx6gE&KVhVHr=eZQ<^h*CU9sVHp^)gg(~ z*)}6uMI15zwehlH1!*@aup6?Ft?o|6r&*!TNFIH8^^2mB#S^oOyc5nkE_WIe3|}hD zpVay@&1+M-F)%UU{|rNm$|)&#^WQTl3g)KXco|~Se%1!JyV|OQ-|943Pj!fuvb^jI z7E#JyN;NoZ7h^(j_dW&rJPcBRTt#1WKzJ&ZU}Rt;CCK6DhScx2A1RPJ$4U)+^m#68 zb>3Hf)83-ufK}zK^ih-k%bD%pE#c=0m~7TIFW#)5%gzCx@w07Z*y%NBq&Vr=%#&cZ z0uN}$KJ~=W81t0qeLR&iwQG12Ukg)ALgS>ICvbCd>3Fi~t!>qzM!1~jl$}%i?-!}2 zu~IWWq{eJ0N=tEe8ShO^1@L7u5>+<7R`2+(pf#1*Kr~H*jn|D76QJU)fcrc~pt{Ue1@qiZa>EhsOJZ4_25I7kFE+FevM@o&|O1pVA7Z!+e$VqP2pnL7t%rjzXR zDZlf@6kIpBUiU0`w)J$+J5E;42z^fZE>QlNMVA&w@OHBr&oXaUoXI@%h>e%Rr$FPzXJi&4S+U?CayzWFp@DWoDrw&+%UYPrj?m<0dzx8{+WuVbSOjN{~f zk;kldDI2lqlwTcX7~Ib7`aD^mQ9Yp7$(zU-{Up+bmU>*?)85O((C}(b`z>IDW+I-7 z<4>>4u5;s0_(fcp+l%SzF0=legWuDTL#MG^R`|~Fx-!Neh0n6RT>YF|9i^0?fwF;f z@AH0&sM?RZQI89yesPeFiDdq8|56tmEA_mvtWHS|wXGqyf7H5YxWJ+-ielSN8P+Xl zWl6Y;j1AYl{wHE7zaHHz$4ZC7-R%;^>k!9EZP5`lDxs7xM5jOOh$zEXbdn~(HIlYt zLeM7veeMDl#}flrqdRxW`aLF*llQ`Biqm9Vm*F#UGAQQ|bPDQptQ5PTrgI^>8>SO8 zKihVVp1~a()dm04e?Y(@y!bHcFUc7a^61QBnKA zi+!hl>=@VOSYkf4I9<^_ONPd5-aXmB8@)3D&OSRKm{>V}bU^5f^cSFM7=`p{?rJO# z;9gC|;(S(@W6=qGSaFLTClE_IMpUGf*LwdMJ|8ZQ;I-tU5Pk!O>p<&dRIoSTAXCG5 zKyrU`3re3KdY(%9ZA|Z_=xhHnNPrdy%5EU}W+(S`6s#r3#FA?-{Df}sKM))a;*mJk zFB8J+9@iAF>K6{&wi_$G%38k=#bC73UN&Wa1ulOl8Ya%2UuoW}V8Imp3gop~2;OKS ziL))M%KheooZl5~J>elrc>(vs&9FE<9HeH;PGiLnl=5ui)7EH0St#U|Go^$4=7KxM z?nxmcUqf&}v@>gPysGRmk|VJKoKPVosRuoJ?;$uc*(0Eyv6n&qin8j6NxB56q7jm; z<`nn%7a|QCLdMJEt{{%EQt`A+2o7X95+J##2_@v=*1#RtkTn3qyhS#;6+pO%oo|wH zo4pkD4Lm(u)0;ebsmMcrYb6wbN=@y`L?gBWC4 z`M)3m)&%eHA;`6cp>b&okzZImXDiwi$UJvi&Pq~jDc${Cm z1j!zy` z`VPbC!74JXOur-xPS}&+jMtmvGpfDR?toVD%}Qf zka+*2^wFoQs=Bw!W+lLm=Rk+0QJ@5tDu?%MpA9ufVoApCm8S1du-Wx|Bke+gx;qLK zbT?2rjkw4J?hpJ$?|B+qDbcXZBd_W)C}U3G36~$$I+KRhAxqL;FYycTp6hG|LI2n4 zS^?PKU8)Ds!px#8=~-uq=xKjcl{dC^*qnQ}0(v5%AHxG1Yn?|6V~3Ys-WG{bfi_0H zy-n^?kBI;Po0_Wimoo)zqo|_QQue?XE&~B+-KQ5BJZ65^f5OP3Q(;s^I4SM&^yRZZ z54ZiNtMi^4$T)x%V03$GZ>*Olo5qtU7Rb7I(kBpTfU1!qR^;(Hq*3CR<#&>^cekOPPn~ zCRIsS^ZlZj)a-c~ka%U^Wz0wxs)<(#ZNm5d` zK|^4-Q-Z*w(wt(7;?9=S6iabZX1Z9M@xU|OJnc#>3rVd{&0DMtsKeAwBmBY#`!()u zptCFNJ}1ueeZ2bG``*>9FlQr*K=emVX_UctKvWQ|XtsZ8@m{IQH6lr%Rt~@ zy-OW9Tm&fLDStZ?}G#R3uFx}9M)It7bNeTa4gQHxM>X!5*y#DW~B)k8FS zHWLsLTg9Ag_A6;73t!4g^2)gfb6X=#BI2kDh&cliTc3Cj1I^$4jOZ(HSrP4hcm?Gr zvp23UQRJF==s7hD%cc@TX~6s$)tG#k!X1YsNA^Tvw|H<)$eZ8By&OaQBC1mf@9lrE zxoGs}^GAPUyewo;;b%Dx;&gDL;d2(>D(aeesw-`#PfOZ51r;9Pi~_+A^k>H)7!^K^51y7%1ZcgNn=*C#sgyIl*uMbEjM_x?R|_WYfQY}3D9;iw*Kd3uxyfq*07NDbrNpM++}Aqes$+h3yT>Y zsT+o69Wrh#Y(wmOg%=EJ(<=Z! ztPjmFHm{ns=H6nEYb@PBV!;cnVYEg{h`+|tYpA%ny@suu-=0LupKmVc`p;v(2L5-| ziXbPc(X#ps5u+ge&eaj?omQ)QPJN36c2(jE?$v@~?cA1Ik7RDE1hKsF`4Rf# z^2OdkG4>CS6CONOx{{aRn4*Q+R)E!DSyQe{)}PXD1iRj$WFCXjumH`i!1N;!5S9!G zl*LQF9tg=1@`Is()hzV5s5OU+Es--kP}ixIZQD*jBE=BpB?sR`j44Nx#i->w3}=Z2 zgdPSF1B1OsKshi?>dH;Tr@A%&_+{s^G1K2ycABg|0!Cib@xoKI65A%Iu1@mYs9=hf zBIAtVrwJv5^k;xHqb^SFJ09dlp-^Px1{KQEQ4k_=M+DcDE#>a~I*4K^*8FEY zG9iIW#^d`;6&iyAJsPufMC`sqFK4vF_7SiQxq#n!$bx1hz+I__ z>dNw#_VEjok`t=i2NNMIFmGf1l`)UGmGi|>;2`*c1XOLRt3W~eDD63mm?+iHiMk1k$D=if(nG0fbvqZmY}n*DJTKvHlx7KxAEMnQZnRi^rDi zOWzYCgD*SdGh~*}vu`mEJu6u$d+5dQ*WP0ZHEKDD{j0YrLJLvL)kU$8Zn4hiCW(Bk zANla!yJMuBEDtwfOJ<3N-(p�>>xu-*wN1#U!eZvFIZcgPofHWXn=?dXgml+Vf!8 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 D=kEpn literal 0 HcmV?d00001 diff --git a/Docs/Diagrams/SDWebImageManagerClassDiagram.png b/Docs/Diagrams/SDWebImageManagerClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..a5e334925c45c808dccc1aa32928909b3beb6a23 GIT binary patch literal 285557 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%0D1PlAZCAR(Vr6(PvTLRSs~wT1Y1- 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%0D8R~jF&*vK`4E;=IJ?%y~{iwc@-~PnAqTP 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 z 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 literal 0 HcmV?d00001 diff --git a/Tests/Tests/SDWebImageDecoderTests.m b/Tests/Tests/SDWebImageDecoderTests.m index 13a2bc59..74c8605c 100644 --- a/Tests/Tests/SDWebImageDecoderTests.m +++ b/Tests/Tests/SDWebImageDecoderTests.m @@ -10,6 +10,7 @@ #import "SDTestCase.h" #import #import +#import #import #import #import @@ -116,6 +117,13 @@ isAnimatedImage:YES]; } +- (void)test11ThatAPNGPCoderWorks { + NSURL *animatedWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageAnimated" withExtension:@"apng"]; + [self verifyCoder:[SDWebImageAPNGCoder sharedCoder] + withLocalImageURL:animatedWebPURL + isAnimatedImage:YES]; +} + - (void)test20ThatOurGIFCoderWorksNotFLAnimatedImage { NSURL *gifURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImage" withExtension:@"gif"]; [self verifyCoder:[SDWebImageGIFCoder sharedCoder] From 915278bfd8221a039681a71aba354d658d79ec60 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 29 Mar 2018 19:42:33 +0800 Subject: [PATCH 075/361] Update the comments and demo for macOS --- Examples/SDWebImage Demo/MasterViewController.m | 2 +- Examples/SDWebImage OSX Demo/ViewController.m | 3 ++- SDWebImage/SDAnimatedImageRep.h | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Examples/SDWebImage Demo/MasterViewController.m b/Examples/SDWebImage Demo/MasterViewController.m index a5ba345d..9def6051 100644 --- a/Examples/SDWebImage Demo/MasterViewController.m +++ b/Examples/SDWebImage Demo/MasterViewController.m @@ -63,7 +63,7 @@ @"http://www.httpwatch.com/httpgallery/authentication/authenticatedimage/default.aspx?0.35786508303135633", // requires HTTP auth, used to demo the NTLM auth @"http://assets.sbnation.com/assets/2512203/dogflops.gif", @"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif", - @"https://raw.githubusercontent.com/onevcat/APNGKit/master/TestImages/APNG-cube.apng", + @"http://apng.onevcat.com/assets/elephant.png", @"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp", @"http://www.ioncannon.net/wp-content/uploads/2011/06/test9.webp", @"http://littlesvr.ca/apng/images/SteamEngine.webp", diff --git a/Examples/SDWebImage OSX Demo/ViewController.m b/Examples/SDWebImage OSX Demo/ViewController.m index 4d5d9b0d..eeda3c7a 100644 --- a/Examples/SDWebImage OSX Demo/ViewController.m +++ b/Examples/SDWebImage OSX Demo/ViewController.m @@ -28,11 +28,12 @@ [super viewDidLoad]; // For animated GIF rendering, set `animates` to YES or will only show the first frame + self.imageView2.animates = YES; // `SDAnimatedImageRep` be can used for built-in `NSImageView` to support better GIF & APNG rendering self.imageView3.animates = YES; self.imageView4.animates = YES; self.imageView1.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator; [self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"]]; - [self.imageView2 sd_setImageWithURL:[NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp"]]; + [self.imageView2 sd_setImageWithURL:[NSURL URLWithString:@"https:raw.githubusercontent.com/onevcat/APNGKit/master/TestImages/APNG-cube.apng"]]; [self.imageView3 sd_setImageWithURL:[NSURL URLWithString:@"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"]]; self.imageView4.wantsLayer = YES; self.imageView4.sd_imageTransition = SDWebImageTransition.fadeTransition; diff --git a/SDWebImage/SDAnimatedImageRep.h b/SDWebImage/SDAnimatedImageRep.h index c794c4b8..32da091b 100644 --- a/SDWebImage/SDAnimatedImageRep.h +++ b/SDWebImage/SDAnimatedImageRep.h @@ -12,6 +12,7 @@ // A subclass of `NSBitmapImageRep` to fix that GIF loop count issue because `NSBitmapImageRep` will reset `NSImageCurrentFrameDuration` by using `kCGImagePropertyGIFDelayTime` but not `kCGImagePropertyGIFUnclampedDelayTime`. // Built in GIF coder use this instead of `NSBitmapImageRep` for better GIF rendering. If you do not want this, only enable `SDWebImageImageIOCoder`, which just call `NSImage` API and actually use `NSBitmapImageRep` for GIF image. +// This also support APNG format using `SDWebImageAPNGCoder`. Which provide full alpha-channel support and the correct duration match the `kCGImagePropertyAPNGUnclampedDelayTime`. @interface SDAnimatedImageRep : NSBitmapImageRep From d5cc827bf86015ae7bde9f7472bcc23d69fbe596 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 29 Mar 2018 20:28:50 +0800 Subject: [PATCH 076/361] Move the animated image files into single group --- SDWebImage.xcodeproj/project.pbxproj | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 8700c40f..c17c2136 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -436,6 +436,11 @@ 32CF1C101FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; 32CF1C111FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; 32CF1C121FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; + 32EB6D8E206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; + 32EB6D8F206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; + 32EB6D90206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; + 32EB6D91206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; + 32EB6D92206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; 32F7C06F2030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32F7C0702030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32F7C0712030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1723,8 +1728,6 @@ 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */, 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */, 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */, - 320224B9203979BA00E9F285 /* SDAnimatedImageRep.h */, - 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */, ); name = Decoder; sourceTree = ""; @@ -1787,6 +1790,8 @@ 32484757201775F600AF9E5A /* SDAnimatedImageView.m */, 32484758201775F600AF9E5A /* SDAnimatedImageView+WebCache.h */, 3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */, + 320224B9203979BA00E9F285 /* SDAnimatedImageRep.h */, + 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */, ); name = ImageView; sourceTree = ""; @@ -3044,6 +3049,7 @@ 323F8C171F38EF770092B609 /* muxinternal.c in Sources */, 323F8BB11F38EF770092B609 /* picture_rescale_enc.c in Sources */, 80377DB21F2F66A700F89830 /* cost_mips32.c in Sources */, + 32EB6D90206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, 80377DC81F2F66A700F89830 /* filters_msa.c in Sources */, 43CE757B1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, 00733A571BC4880000A5A117 /* SDImageCache.m in Sources */, @@ -3078,6 +3084,7 @@ 329A18601FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, 80377D541F2F66A700F89830 /* rescaler_mips32.c in Sources */, 80377D331F2F66A700F89830 /* dec.c in Sources */, + 32EB6D92206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, 323F8BAF1F38EF770092B609 /* picture_rescale_enc.c in Sources */, 80377D3F1F2F66A700F89830 /* filters_neon.c in Sources */, 80377D3E1F2F66A700F89830 /* filters_msa.c in Sources */, @@ -3232,6 +3239,7 @@ 329A18631FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, 80377E231F2F66A800F89830 /* rescaler_mips32.c in Sources */, 80377E021F2F66A800F89830 /* dec.c in Sources */, + 32EB6D8F206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, 323F8BB21F38EF770092B609 /* picture_rescale_enc.c in Sources */, 80377E0E1F2F66A800F89830 /* filters_neon.c in Sources */, 80377E0D1F2F66A800F89830 /* filters_msa.c in Sources */, @@ -3667,6 +3675,7 @@ 80377D7F1F2F66A700F89830 /* enc_sse2.c in Sources */, 323F8C161F38EF770092B609 /* muxinternal.c in Sources */, 323F8BB01F38EF770092B609 /* picture_rescale_enc.c in Sources */, + 32EB6D8E206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, 80377D6D1F2F66A700F89830 /* cost_mips32.c in Sources */, 80377D831F2F66A700F89830 /* filters_msa.c in Sources */, 4A2CAE341AB4BB7500B6BC39 /* UIImageView+HighlightedWebCache.m in Sources */, @@ -3825,6 +3834,7 @@ 323F8C141F38EF770092B609 /* muxinternal.c in Sources */, 323F8BAE1F38EF770092B609 /* picture_rescale_enc.c in Sources */, 80377CE31F2F66A100F89830 /* cost_mips32.c in Sources */, + 32EB6D91206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, 80377CF91F2F66A100F89830 /* filters_msa.c in Sources */, 5D5B9145188EE8DD006D06BD /* NSData+ImageContentType.m in Sources */, 53EDFB8C17623F7C00698166 /* UIImage+MultiFormat.m in Sources */, From 92f3d2c795cf07c7464f9e19e63755505b5de690 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 31 Mar 2018 17:33:18 +0800 Subject: [PATCH 077/361] Remove the `maxConcurrentDownloads`, which can be set from downloader configuration. Rename the `prefetcherQueue` to `delegateQueue` to match the correct description. Fix the delegateQueue to async dispatch, avoid immediate callback cause recursion call(Match previous behavior) --- SDWebImage/SDWebImagePrefetcher.h | 16 +++++++--------- SDWebImage/SDWebImagePrefetcher.m | 23 +++++++++-------------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/SDWebImage/SDWebImagePrefetcher.h b/SDWebImage/SDWebImagePrefetcher.h index 9ae1678a..2f81c417 100644 --- a/SDWebImage/SDWebImagePrefetcher.h +++ b/SDWebImage/SDWebImagePrefetcher.h @@ -58,15 +58,11 @@ typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, @interface SDWebImagePrefetcher : NSObject /** - * The web image manager + * The web image manager used by prefetcher to prefetch images. + * @note You can specify a standalone manager and downloader with custom configuration suitable for image prefetching. Such as `currentDownloadCount` or `downloadTimeout`. */ @property (strong, nonatomic, readonly, nonnull) SDWebImageManager *manager; -/** - * Maximum number of URLs to prefetch at the same time. Defaults to 3. - */ -@property (nonatomic, assign) NSUInteger maxConcurrentDownloads; - /** * The options for prefetcher. Defaults to SDWebImageLowPriority. */ @@ -79,16 +75,18 @@ typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, /** * Queue options for prefetcher when call the progressBlock, completionBlock and delegate methods. Defaults to Main Queue. + * @note The call is asynchronously to avoid blocking target queue. + * @note The delegate queue should be set before any prefetching start and may not be changed during prefetching to avoid thread-safe problem. */ -@property (strong, nonatomic, nonnull) dispatch_queue_t prefetcherQueue; +@property (strong, nonatomic, nonnull) dispatch_queue_t delegateQueue; /** - * The delegate for the prefetcher. + * The delegate for the prefetcher. Defatuls to nil. */ @property (weak, nonatomic, nullable) id delegate; /** - * Returns the global shared image prefetcher instance. + * Returns the global shared image prefetcher instance. It use a standalone manager which is different from shared manager. */ @property (nonatomic, class, readonly, nonnull) SDWebImagePrefetcher *sharedImagePrefetcher; diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index dfb82a10..89e13c6f 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -51,20 +51,11 @@ _manager = manager; _runningTokens = [NSMutableSet set]; _options = SDWebImageLowPriority; - _prefetcherQueue = dispatch_get_main_queue(); - self.maxConcurrentDownloads = 3; + _delegateQueue = dispatch_get_main_queue(); } return self; } -- (void)setMaxConcurrentDownloads:(NSUInteger)maxConcurrentDownloads { - self.manager.imageDownloader.maxConcurrentDownloads = maxConcurrentDownloads; -} - -- (NSUInteger)maxConcurrentDownloads { - return self.manager.imageDownloader.maxConcurrentDownloads; -} - #pragma mark - Prefetch - (nullable SDWebImagePrefetchToken *)prefetchURLs:(nullable NSArray *)urls { return [self prefetchURLs:urls progress:nil completed:nil]; @@ -138,9 +129,11 @@ return; } BOOL shouldCallDelegate = [self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)]; - dispatch_queue_async_safe(self.prefetcherQueue, ^{ + NSUInteger finishedCount = [self tokenFinishedCount]; + NSUInteger totalCount = [self tokenTotalCount]; + dispatch_async(self.delegateQueue, ^{ if (shouldCallDelegate) { - [self.delegate imagePrefetcher:self didPrefetchURL:url finishedCount:[self tokenFinishedCount] totalCount:[self tokenTotalCount]]; + [self.delegate imagePrefetcher:self didPrefetchURL:url finishedCount:finishedCount totalCount:totalCount]; } if (token.progressBlock) { token.progressBlock((NSUInteger)token->_finishedCount, (NSUInteger)token.totalCount); @@ -153,9 +146,11 @@ return; } BOOL shoulCallDelegate = [self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)] && ([self countOfRunningTokens] == 1); // last one - dispatch_queue_async_safe(self.prefetcherQueue, ^{ + NSUInteger totalCount = [self tokenTotalCount]; + NSUInteger skippedCount = [self tokenSkippedCount]; + dispatch_async(self.delegateQueue, ^{ if (shoulCallDelegate) { - [self.delegate imagePrefetcher:self didFinishWithTotalCount:[self tokenTotalCount] skippedCount:[self tokenSkippedCount]]; + [self.delegate imagePrefetcher:self didFinishWithTotalCount:totalCount skippedCount:skippedCount]; } if (token.completionBlock) { token.completionBlock((NSUInteger)token->_finishedCount, (NSUInteger)token->_skippedCount); From 07494e48953bf2f34d67bb565196b1a8f2e1c39e Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 31 Mar 2018 17:59:28 +0800 Subject: [PATCH 078/361] Fix the manager's wrong nullable property to nonnull --- SDWebImage/SDWebImageManager.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index f0206e99..98b26d48 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -191,10 +191,21 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; */ @interface SDWebImageManager : NSObject +/** + * The delegate for manager. Defatuls to nil. + */ @property (weak, nonatomic, nullable) id delegate; -@property (strong, nonatomic, readonly, nullable) SDImageCache *imageCache; -@property (strong, nonatomic, readonly, nullable) SDWebImageDownloader *imageDownloader; +/** + * The image cache used by manager to query image cache. + */ +@property (strong, nonatomic, readonly, nonnull) SDImageCache *imageCache; + +/** + * The image downloader used by manager to download image. + * @note If you specify a non-shared downloader, don't forget to call `invalidateSessionAndCancel:` at proper time to avoid memory leak. + */ +@property (strong, nonatomic, readonly, nonnull) SDWebImageDownloader *imageDownloader; /** The image transformer for manager. It's used for image transform after the image load finished and store the transformed image to cache, see `SDWebImageTransformer`. From bc164d636946ef1725cb7c217672e6015b880bcd Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 31 Mar 2018 21:44:53 +0800 Subject: [PATCH 079/361] Fix prefetcher thread-safe problem using stdatomic instead of OSAtomic. Also fix test. --- SDWebImage/SDWebImagePrefetcher.m | 45 ++++++++++++++----------- Tests/Tests/SDWebImagePrefetcherTests.m | 33 ++++++++++-------- 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index 89e13c6f..98991703 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -7,16 +7,17 @@ */ #import "SDWebImagePrefetcher.h" -#import +#import @interface SDWebImagePrefetchToken () { @public - int64_t _skippedCount; - int64_t _finishedCount; + // These value are just used as incrementing counter, keep thread-safe using memory_order_relaxed for performance. + atomic_ulong _skippedCount; + atomic_ulong _finishedCount; + atomic_ulong _totalCount; } @property (nonatomic, copy, readwrite) NSArray *urls; -@property (nonatomic, assign) int64_t totalCount; @property (nonatomic, strong) NSPointerArray *operations; @property (nonatomic, weak) SDWebImagePrefetcher *prefetcher; @property (nonatomic, copy, nullable) SDWebImagePrefetcherCompletionBlock completionBlock; @@ -72,10 +73,10 @@ } SDWebImagePrefetchToken *token = [SDWebImagePrefetchToken new]; token.prefetcher = self; + token.urls = urls; token->_skippedCount = 0; token->_finishedCount = 0; - token.urls = urls; - token.totalCount = urls.count; + token->_totalCount = token.urls.count; token.operations = [NSPointerArray weakObjectsPointerArray]; token.progressBlock = progressBlock; token.completionBlock = completionBlock; @@ -92,16 +93,16 @@ if (!finished) { return; } - OSAtomicIncrement64(&(token->_finishedCount)); + atomic_fetch_add_explicit(&(token->_finishedCount), 1, memory_order_relaxed); if (error) { // Add last failed - OSAtomicIncrement64(&(token->_skippedCount)); + atomic_fetch_add_explicit(&(token->_skippedCount), 1, memory_order_relaxed); } // Current operation finished [sself callProgressBlockForToken:token imageURL:imageURL]; - if (token->_finishedCount + token->_skippedCount == token.totalCount) { + if (atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed) + atomic_load_explicit(&(token->_skippedCount), memory_order_relaxed) >= atomic_load_explicit(&(token->_totalCount), memory_order_relaxed)) { // All finished [sself callCompletionBlockForToken:token]; [sself removeRunningToken:token]; @@ -129,14 +130,16 @@ return; } BOOL shouldCallDelegate = [self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)]; - NSUInteger finishedCount = [self tokenFinishedCount]; - NSUInteger totalCount = [self tokenTotalCount]; + NSUInteger tokenFinishedCount = [self tokenFinishedCount]; + NSUInteger tokenTotalCount = [self tokenTotalCount]; + NSUInteger finishedCount = atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed); + NSUInteger totalCount = atomic_load_explicit(&(token->_totalCount), memory_order_relaxed); dispatch_async(self.delegateQueue, ^{ if (shouldCallDelegate) { - [self.delegate imagePrefetcher:self didPrefetchURL:url finishedCount:finishedCount totalCount:totalCount]; + [self.delegate imagePrefetcher:self didPrefetchURL:url finishedCount:tokenFinishedCount totalCount:tokenTotalCount]; } if (token.progressBlock) { - token.progressBlock((NSUInteger)token->_finishedCount, (NSUInteger)token.totalCount); + token.progressBlock(finishedCount, totalCount); } }); } @@ -146,14 +149,16 @@ return; } BOOL shoulCallDelegate = [self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)] && ([self countOfRunningTokens] == 1); // last one - NSUInteger totalCount = [self tokenTotalCount]; - NSUInteger skippedCount = [self tokenSkippedCount]; + NSUInteger tokenTotalCount = [self tokenTotalCount]; + NSUInteger tokenSkippedCount = [self tokenSkippedCount]; + NSUInteger finishedCount = atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed); + NSUInteger skippedCount = atomic_load_explicit(&(token->_skippedCount), memory_order_relaxed); dispatch_async(self.delegateQueue, ^{ if (shoulCallDelegate) { - [self.delegate imagePrefetcher:self didFinishWithTotalCount:totalCount skippedCount:skippedCount]; + [self.delegate imagePrefetcher:self didFinishWithTotalCount:tokenTotalCount skippedCount:tokenSkippedCount]; } if (token.completionBlock) { - token.completionBlock((NSUInteger)token->_finishedCount, (NSUInteger)token->_skippedCount); + token.completionBlock(finishedCount, skippedCount); } }); } @@ -163,7 +168,7 @@ NSUInteger tokenTotalCount = 0; @synchronized (self.runningTokens) { for (SDWebImagePrefetchToken *token in self.runningTokens) { - tokenTotalCount += token.totalCount; + tokenTotalCount += atomic_load_explicit(&(token->_totalCount), memory_order_relaxed); } } return tokenTotalCount; @@ -173,7 +178,7 @@ NSUInteger tokenSkippedCount = 0; @synchronized (self.runningTokens) { for (SDWebImagePrefetchToken *token in self.runningTokens) { - tokenSkippedCount += token->_skippedCount; + tokenSkippedCount += atomic_load_explicit(&(token->_skippedCount), memory_order_relaxed); } } return tokenSkippedCount; @@ -183,7 +188,7 @@ NSUInteger tokenFinishedCount = 0; @synchronized (self.runningTokens) { for (SDWebImagePrefetchToken *token in self.runningTokens) { - tokenFinishedCount += token->_finishedCount; + tokenFinishedCount += atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed); } } return tokenFinishedCount; diff --git a/Tests/Tests/SDWebImagePrefetcherTests.m b/Tests/Tests/SDWebImagePrefetcherTests.m index 0a2bc795..b05edb0c 100644 --- a/Tests/Tests/SDWebImagePrefetcherTests.m +++ b/Tests/Tests/SDWebImagePrefetcherTests.m @@ -13,9 +13,9 @@ @interface SDWebImagePrefetcherTests : SDTestCase @property (nonatomic, strong) SDWebImagePrefetcher *prefetcher; -@property (nonatomic, assign) NSUInteger finishedCount; -@property (nonatomic, assign) NSUInteger skippedCount; -@property (nonatomic, assign) NSUInteger totalCount; +@property (atomic, assign) NSUInteger finishedCount; +@property (atomic, assign) NSUInteger skippedCount; +@property (atomic, assign) NSUInteger totalCount; @end @@ -112,22 +112,27 @@ - (void)test05PrefecherDelegateWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Prefetcher delegate failed"]; - NSArray *imageURLs = @[@"http://via.placeholder.com/20x20.jpg", - @"http://via.placeholder.com/30x30.jpg", - @"http://via.placeholder.com/40x40.jpg"]; + // This test also test large URLs and thread-safe problem. You can tested with 2000 urls and get the correct result locally. However, due to the limit of CI, 20 is enough. + NSMutableArray *imageURLs = [NSMutableArray arrayWithCapacity:20]; + for (size_t i = 1; i <= 20; i++) { + NSString *url = [NSString stringWithFormat:@"http://via.placeholder.com/%zux%zu.jpg", i, i]; + [imageURLs addObject:[NSURL URLWithString:url]]; + } self.prefetcher = [SDWebImagePrefetcher new]; self.prefetcher.delegate = self; // Current implementation, the delegate method called before the progressBlock and completionBlock - [self.prefetcher prefetchURLs:imageURLs progress:^(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls) { - expect(self.finishedCount).to.equal(noOfFinishedUrls); - expect(self.totalCount).to.equal(noOfTotalUrls); - } completed:^(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls) { - expect(self.finishedCount).to.equal(noOfFinishedUrls); - expect(self.skippedCount).to.equal(noOfSkippedUrls); - [expectation fulfill]; + [[SDImageCache sharedImageCache] clearDiskOnCompletion:^{ + [self.prefetcher prefetchURLs:[imageURLs copy] progress:^(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls) { + expect(self.finishedCount).to.equal(noOfFinishedUrls); + expect(self.totalCount).to.equal(noOfTotalUrls); + } completed:^(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls) { + expect(self.finishedCount).to.equal(noOfFinishedUrls); + expect(self.skippedCount).to.equal(noOfSkippedUrls); + [expectation fulfill]; + }]; }]; - [self waitForExpectationsWithCommonTimeout]; + [self waitForExpectationsWithTimeout:kAsyncTestTimeout * 20 handler:nil]; } - (void)imagePrefetcher:(SDWebImagePrefetcher *)imagePrefetcher didFinishWithTotalCount:(NSUInteger)totalCount skippedCount:(NSUInteger)skippedCount { From f1b5e947990588517f57055cfcd9b3b7495b3e11 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 31 Mar 2018 22:08:27 +0800 Subject: [PATCH 080/361] Update the comments --- SDWebImage/SDWebImagePrefetcher.m | 1 + 1 file changed, 1 insertion(+) diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index 98991703..55713cfe 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -11,6 +11,7 @@ @interface SDWebImagePrefetchToken () { @public + // Though current implementation, `SDWebImageManager` completion block is always on main queue. But however, there is no guarantee in docs. And we may introduce config to specify custom queue in the future. // These value are just used as incrementing counter, keep thread-safe using memory_order_relaxed for performance. atomic_ulong _skippedCount; atomic_ulong _finishedCount; From 851ee7d3725cbbc55e6da6d2aaa9ff5ffb1930fa Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 1 Apr 2018 00:11:15 +0800 Subject: [PATCH 081/361] Update the prefetcher test case naming --- Tests/Tests/SDWebImagePrefetcherTests.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Tests/SDWebImagePrefetcherTests.m b/Tests/Tests/SDWebImagePrefetcherTests.m index b05edb0c..0b62a568 100644 --- a/Tests/Tests/SDWebImagePrefetcherTests.m +++ b/Tests/Tests/SDWebImagePrefetcherTests.m @@ -109,8 +109,8 @@ [self waitForExpectationsWithCommonTimeout]; } -- (void)test05PrefecherDelegateWorks { - XCTestExpectation *expectation = [self expectationWithDescription:@"Prefetcher delegate failed"]; +- (void)test05PrefetchLargeURLsAndDelegateWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Prefetch large URLs and delegate failed"]; // This test also test large URLs and thread-safe problem. You can tested with 2000 urls and get the correct result locally. However, due to the limit of CI, 20 is enough. NSMutableArray *imageURLs = [NSMutableArray arrayWithCapacity:20]; From d751b20652da452136bdc4f6e33b418d24658121 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 1 Apr 2018 22:02:50 +0800 Subject: [PATCH 082/361] Move all the webcache options into the `SDWebImageDefine.h` files to avoid import of `SDWebImageManager.h` and include cycle. --- SDWebImage/SDWebImageDefine.h | 123 ++++++++++++++++++++++++++++++++- SDWebImage/SDWebImageManager.h | 118 ------------------------------- 2 files changed, 122 insertions(+), 119 deletions(-) diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index 604e0cd9..c2e4df27 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -32,7 +32,128 @@ FOUNDATION_EXPORT CGFloat SDImageScaleForKey(NSString * _Nullable key); */ FOUNDATION_EXPORT UIImage * _Nullable SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image); -#pragma mark - Context option +#pragma mark - WebCache Options + +typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { + /** + * By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying. + * This flag disable this blacklisting. + */ + SDWebImageRetryFailed = 1 << 0, + + /** + * By default, image downloads are started during UI interactions, this flags disable this feature, + * leading to delayed download on UIScrollView deceleration for instance. + */ + SDWebImageLowPriority = 1 << 1, + + /** + * This flag disables on-disk caching after the download finished, only cache in memory + */ + SDWebImageCacheMemoryOnly = 1 << 2, + + /** + * This flag enables progressive download, the image is displayed progressively during download as a browser would do. + * By default, the image is only displayed once completely downloaded. + */ + SDWebImageProgressiveDownload = 1 << 3, + + /** + * Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed. + * The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation. + * This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics. + * If a cached image is refreshed, the completion block is called once with the cached image and again with the final image. + * + * Use this flag only if you can't make your URLs static with embedded cache busting parameter. + */ + SDWebImageRefreshCached = 1 << 4, + + /** + * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for + * extra time in background to let the request finish. If the background task expires the operation will be cancelled. + */ + SDWebImageContinueInBackground = 1 << 5, + + /** + * Handles cookies stored in NSHTTPCookieStore by setting + * NSMutableURLRequest.HTTPShouldHandleCookies = YES; + */ + SDWebImageHandleCookies = 1 << 6, + + /** + * Enable to allow untrusted SSL certificates. + * Useful for testing purposes. Use with caution in production. + */ + SDWebImageAllowInvalidSSLCertificates = 1 << 7, + + /** + * By default, images are loaded in the order in which they were queued. This flag moves them to + * the front of the queue. + */ + SDWebImageHighPriority = 1 << 8, + + /** + * By default, placeholder images are loaded while the image is loading. This flag will delay the loading + * of the placeholder image until after the image has finished loading. + */ + SDWebImageDelayPlaceholder = 1 << 9, + + /** + * We usually don't apply transform on animated images as most transformers could not manage animated images. + * Use this flag to transform them anyway. + */ + SDWebImageTransformAnimatedImage = 1 << 10, + + /** + * By default, image is added to the imageView after download. But in some cases, we want to + * have the hand before setting the image (apply a filter or add it with cross-fade animation for instance) + * Use this flag if you want to manually set the image in the completion when success + */ + SDWebImageAvoidAutoSetImage = 1 << 11, + + /** + * By default, images are decoded respecting their original size. On iOS, this flag will scale down the + * images to a size compatible with the constrained memory of devices. + * If `SDWebImageProgressiveDownload` flag is set the scale down is deactivated. + */ + SDWebImageScaleDownLargeImages = 1 << 12, + + /** + * By default, we do not query disk data when the image is cached in memory. This mask can force to query disk data at the same time. + * This flag is recommend to be used with `SDWebImageQueryDiskSync` to ensure the image is loaded in the same runloop. + */ + SDWebImageQueryDataWhenInMemory = 1 << 13, + + /** + * By default, we query the memory cache synchronously, disk cache asynchronously. This mask can force to query disk cache synchronously to ensure that image is loaded in the same runloop. + * This flag can avoid flashing during cell reuse if you disable memory cache or in some other cases. + */ + SDWebImageQueryDiskSync = 1 << 14, + + /** + * By default, when the cache missed, the image is download from the network. This flag can prevent network to load from cache only. + */ + SDWebImageFromCacheOnly = 1 << 15, + + /** + * By default, when you use `SDWebImageTransition` to do some view transition after the image load finished, this transition is only applied for image download from the network. This mask can force to apply view transition for memory and disk cache as well. + */ + SDWebImageForceTransition = 1 << 16, + + /** + * By default, we decode the animated image. This flag can force decode the first frame only and produece the static image. + */ + SDWebImageDecodeFirstFrameOnly = 1 << 17, + + /** + * By default, for `SDAnimatedImage`, we decode the animated image frame during rendering to reduce memory usage. However, you can specify to preload all frames into memory to reduce CPU usage when the animated image is shared by lots of imageViews. + * This will actually trigger `preloadAllAnimatedImageFrames` in the background queue(Disk Cache & Download only). + */ + SDWebImagePreloadAllFrames = 1 << 18 +}; + + +#pragma mark - Context Options /** A Dispatch group to maintain setImageBlock and completionBlock. This is used for custom setImageBlock advanced usage, such like perform background task but need to guarantee the completion block is called after setImageBlock. (dispatch_group_t) diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 98b26d48..e5edd7dd 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -12,124 +12,6 @@ #import "SDImageCache.h" #import "SDWebImageTransformer.h" -typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { - /** - * By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying. - * This flag disable this blacklisting. - */ - SDWebImageRetryFailed = 1 << 0, - - /** - * By default, image downloads are started during UI interactions, this flags disable this feature, - * leading to delayed download on UIScrollView deceleration for instance. - */ - SDWebImageLowPriority = 1 << 1, - - /** - * This flag disables on-disk caching after the download finished, only cache in memory - */ - SDWebImageCacheMemoryOnly = 1 << 2, - - /** - * This flag enables progressive download, the image is displayed progressively during download as a browser would do. - * By default, the image is only displayed once completely downloaded. - */ - SDWebImageProgressiveDownload = 1 << 3, - - /** - * Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed. - * The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation. - * This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics. - * If a cached image is refreshed, the completion block is called once with the cached image and again with the final image. - * - * Use this flag only if you can't make your URLs static with embedded cache busting parameter. - */ - SDWebImageRefreshCached = 1 << 4, - - /** - * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for - * extra time in background to let the request finish. If the background task expires the operation will be cancelled. - */ - SDWebImageContinueInBackground = 1 << 5, - - /** - * Handles cookies stored in NSHTTPCookieStore by setting - * NSMutableURLRequest.HTTPShouldHandleCookies = YES; - */ - SDWebImageHandleCookies = 1 << 6, - - /** - * Enable to allow untrusted SSL certificates. - * Useful for testing purposes. Use with caution in production. - */ - SDWebImageAllowInvalidSSLCertificates = 1 << 7, - - /** - * By default, images are loaded in the order in which they were queued. This flag moves them to - * the front of the queue. - */ - SDWebImageHighPriority = 1 << 8, - - /** - * By default, placeholder images are loaded while the image is loading. This flag will delay the loading - * of the placeholder image until after the image has finished loading. - */ - SDWebImageDelayPlaceholder = 1 << 9, - - /** - * We usually don't apply transform on animated images as most transformers could not manage animated images. - * Use this flag to transform them anyway. - */ - SDWebImageTransformAnimatedImage = 1 << 10, - - /** - * By default, image is added to the imageView after download. But in some cases, we want to - * have the hand before setting the image (apply a filter or add it with cross-fade animation for instance) - * Use this flag if you want to manually set the image in the completion when success - */ - SDWebImageAvoidAutoSetImage = 1 << 11, - - /** - * By default, images are decoded respecting their original size. On iOS, this flag will scale down the - * images to a size compatible with the constrained memory of devices. - * If `SDWebImageProgressiveDownload` flag is set the scale down is deactivated. - */ - SDWebImageScaleDownLargeImages = 1 << 12, - - /** - * By default, we do not query disk data when the image is cached in memory. This mask can force to query disk data at the same time. - * This flag is recommend to be used with `SDWebImageQueryDiskSync` to ensure the image is loaded in the same runloop. - */ - SDWebImageQueryDataWhenInMemory = 1 << 13, - - /** - * By default, we query the memory cache synchronously, disk cache asynchronously. This mask can force to query disk cache synchronously to ensure that image is loaded in the same runloop. - * This flag can avoid flashing during cell reuse if you disable memory cache or in some other cases. - */ - SDWebImageQueryDiskSync = 1 << 14, - - /** - * By default, when the cache missed, the image is download from the network. This flag can prevent network to load from cache only. - */ - SDWebImageFromCacheOnly = 1 << 15, - - /** - * By default, when you use `SDWebImageTransition` to do some view transition after the image load finished, this transition is only applied for image download from the network. This mask can force to apply view transition for memory and disk cache as well. - */ - SDWebImageForceTransition = 1 << 16, - - /** - * By default, we decode the animated image. This flag can force decode the first frame only and produece the static image. - */ - SDWebImageDecodeFirstFrameOnly = 1 << 17, - - /** - * By default, for `SDAnimatedImage`, we decode the animated image frame during rendering to reduce memory usage. However, you can specify to preload all frames into memory to reduce CPU usage when the animated image is shared by lots of imageViews. - * This will actually trigger `preloadAllAnimatedImageFrames` in the background queue(Disk Cache & Download only). - */ - SDWebImagePreloadAllFrames = 1 << 18 -}; - typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL); typedef void(^SDInternalCompletionBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL); From 8236dee202485428fdd2347c0000d3d5d89bd3b2 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 2 Apr 2018 03:24:23 +0800 Subject: [PATCH 083/361] Move the context arg after the `options` arg to make Swift ABI clear. Also update all view category to support context arg. --- .../FLAnimatedImageView+WebCache.m | 21 +++- SDWebImage/MKAnnotationView+WebCache.h | 46 +++++++++ SDWebImage/MKAnnotationView+WebCache.m | 20 +++- SDWebImage/NSButton+WebCache.h | 48 +++++++++ SDWebImage/NSButton+WebCache.m | 51 ++++++---- SDWebImage/SDAnimatedImageView+WebCache.h | 24 +++++ SDWebImage/SDAnimatedImageView+WebCache.m | 22 ++++- SDWebImage/SDImageCache.h | 4 +- SDWebImage/SDImageCache.m | 4 +- SDWebImage/SDWebImageDefine.h | 10 +- SDWebImage/SDWebImageDefine.m | 1 + SDWebImage/SDWebImageDownloader.h | 6 +- SDWebImage/SDWebImageDownloader.m | 6 +- SDWebImage/SDWebImageManager.h | 6 +- SDWebImage/SDWebImageManager.m | 21 ++-- SDWebImage/SDWebImagePrefetcher.m | 4 +- SDWebImage/UIButton+WebCache.h | 98 +++++++++++++++++++ SDWebImage/UIButton+WebCache.m | 54 ++++++++-- SDWebImage/UIImageView+HighlightedWebCache.m | 22 ++++- SDWebImage/UIImageView+WebCache.h | 24 +++++ SDWebImage/UIImageView+WebCache.m | 13 ++- SDWebImage/UIView+WebCache.h | 54 +++------- SDWebImage/UIView+WebCache.m | 64 ++++++------ Tests/Tests/SDWebCacheCategoriesTests.m | 2 +- 24 files changed, 495 insertions(+), 130 deletions(-) diff --git a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m index 0744a084..2be6b024 100644 --- a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m +++ b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m @@ -53,17 +53,29 @@ [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; } +- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; +} + - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { dispatch_group_t group = dispatch_group_create(); + SDWebImageMutableContext *mutableContext; + if (context) { + mutableContext = [context mutableCopy]; + } else { + mutableContext = [NSMutableDictionary dictionary]; + } + mutableContext[SDWebImageContextSetImageGroup] = group; __weak typeof(self)weakSelf = self; [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options - operationKey:nil + context:mutableContext setImageBlock:^(UIImage *image, NSData *imageData) { // We could not directlly create the animated image on bacakground queue because it's time consuming, by the time we set it back, the current runloop has passed and the placeholder has been rendered and then replaced with animated image, this cause a flashing. // Previously we use a trick to firstly set the static poster image, then set animated image back to avoid flashing, but this trick fail when using with custom UIView transition. Core Animation will use the current layer state to do rendering, so even we later set it back, the transition will not update. (it's recommended to use `SDWebImageTransition` instead) @@ -103,8 +115,11 @@ } } progress:progressBlock - completed:completedBlock - context:group ? @{SDWebImageContextSetImageGroup : group} : nil]; + completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType, imageURL); + } + }]; } @end diff --git a/SDWebImage/MKAnnotationView+WebCache.h b/SDWebImage/MKAnnotationView+WebCache.h index 0f313af6..7fec73d8 100644 --- a/SDWebImage/MKAnnotationView+WebCache.h +++ b/SDWebImage/MKAnnotationView+WebCache.h @@ -104,6 +104,52 @@ options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock; +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + @end #endif diff --git a/SDWebImage/MKAnnotationView+WebCache.m b/SDWebImage/MKAnnotationView+WebCache.m index 7ea2f557..c228249b 100644 --- a/SDWebImage/MKAnnotationView+WebCache.m +++ b/SDWebImage/MKAnnotationView+WebCache.m @@ -36,20 +36,34 @@ [self sd_setImageWithURL:url placeholderImage:placeholder options:0 completed:completedBlock]; } +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; +} + - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { __weak typeof(self)weakSelf = self; [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options - operationKey:nil + context:context setImageBlock:^(UIImage *image, NSData *imageData) { weakSelf.image = image; } - progress:nil - completed:completedBlock]; + progress:progressBlock + completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType, imageURL); + } + }]; } @end diff --git a/SDWebImage/NSButton+WebCache.h b/SDWebImage/NSButton+WebCache.h index 33f84ba0..0edb7a4b 100644 --- a/SDWebImage/NSButton+WebCache.h +++ b/SDWebImage/NSButton+WebCache.h @@ -128,6 +128,30 @@ progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; +/** + * Set the button `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + #pragma mark - Alternate Image /** @@ -242,6 +266,30 @@ progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; +/** + * Set the button `alternateImage` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the alternateImage. + * @param placeholder The alternateImage to be set initially, until the alternateImage request finishes. + * @param options The options to use when downloading the alternateImage. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * @param progressBlock A block called while alternateImage is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the alternateImage parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the alternateImage was retrieved from the local cache or from the network. + * The fourth parameter is the original alternateImage url. + */ +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + #pragma mark - Cancel /** diff --git a/SDWebImage/NSButton+WebCache.m b/SDWebImage/NSButton+WebCache.m index 3ca080f2..b8f5092b 100644 --- a/SDWebImage/NSButton+WebCache.m +++ b/SDWebImage/NSButton+WebCache.m @@ -14,13 +14,7 @@ #import "UIView+WebCacheOperation.h" #import "UIView+WebCache.h" -static inline NSString * imageOperationKey() { - return @"NSButtonImageOperation"; -} - -static inline NSString * alternateImageOperationKey() { - return @"NSButtonAlternateImageOperation"; -} +static NSString * const SDAlternateImageOperationKey = @"NSButtonAlternateImageOperation"; @implementation NSButton (WebCache) @@ -50,23 +44,28 @@ static inline NSString * alternateImageOperationKey() { [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; } +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; +} + - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { self.sd_currentImageURL = url; - - __weak typeof(self)weakSelf = self; [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options - operationKey:imageOperationKey() - setImageBlock:^(NSImage * _Nullable image, NSData * _Nullable imageData) { - weakSelf.image = image; - } + context:context + setImageBlock:nil progress:progressBlock - completed:completedBlock]; + completed:^(NSImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType, imageURL); + } + }]; } #pragma mark - Alternate Image @@ -95,33 +94,49 @@ static inline NSString * alternateImageOperationKey() { [self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; } +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; +} + - (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { self.sd_currentAlternateImageURL = url; + SDWebImageMutableContext *mutableContext; + if (context) { + mutableContext = [context mutableCopy]; + } else { + mutableContext = [NSMutableDictionary dictionary]; + } + mutableContext[SDWebImageContextSetImageOperationKey] = SDAlternateImageOperationKey; __weak typeof(self)weakSelf = self; [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options - operationKey:alternateImageOperationKey() + context:mutableContext setImageBlock:^(NSImage * _Nullable image, NSData * _Nullable imageData) { weakSelf.alternateImage = image; } progress:progressBlock - completed:completedBlock]; + completed:^(NSImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType, imageURL); + } + }]; } #pragma mark - Cancel - (void)sd_cancelCurrentImageLoad { - [self sd_cancelImageLoadOperationWithKey:imageOperationKey()]; + [self sd_cancelImageLoadOperationWithKey:NSStringFromClass([self class])]; } - (void)sd_cancelCurrentAlternateImageLoad { - [self sd_cancelImageLoadOperationWithKey:alternateImageOperationKey()]; + [self sd_cancelImageLoadOperationWithKey:SDAlternateImageOperationKey]; } #pragma mar - Private diff --git a/SDWebImage/SDAnimatedImageView+WebCache.h b/SDWebImage/SDAnimatedImageView+WebCache.h index ab528b70..6a1b0fc1 100644 --- a/SDWebImage/SDAnimatedImageView+WebCache.h +++ b/SDWebImage/SDAnimatedImageView+WebCache.h @@ -121,6 +121,30 @@ progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + @end #endif diff --git a/SDWebImage/SDAnimatedImageView+WebCache.m b/SDWebImage/SDAnimatedImageView+WebCache.m index 4ec46e7d..fa9407bb 100644 --- a/SDWebImage/SDAnimatedImageView+WebCache.m +++ b/SDWebImage/SDAnimatedImageView+WebCache.m @@ -39,21 +39,35 @@ [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; } +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; +} + - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { Class animatedImageClass = [SDAnimatedImage class]; - SDWebImageContext *context = @{SDWebImageContextAnimatedImageClass : animatedImageClass}; + SDWebImageMutableContext *mutableContext; + if (context) { + mutableContext = [context mutableCopy]; + } else { + mutableContext = [NSMutableDictionary dictionary]; + } + mutableContext[SDWebImageContextAnimatedImageClass] = animatedImageClass; [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options - operationKey:nil + context:mutableContext setImageBlock:nil progress:progressBlock - completed:completedBlock - context:context]; + completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType, imageURL); + } + }]; } @end diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index ea8b3a1a..ddc93dd0 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -216,12 +216,12 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er * * @param key The unique key used to store the wanted image * @param options A mask to specify options to use for this cache query - * @param doneBlock The completion block. Will not get called if the operation is cancelled * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * @param doneBlock The completion block. Will not get called if the operation is cancelled * * @return a NSOperation instance containing the cache op */ -- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock context:(nullable SDWebImageContext *)context; +- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context done:(nullable SDCacheQueryCompletedBlock)doneBlock; /** * Synchronously query the memory cache. diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 8c069bec..aac09322 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -530,10 +530,10 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } - (nullable NSOperation *)queryCacheOperationForKey:(NSString *)key options:(SDImageCacheOptions)options done:(SDCacheQueryCompletedBlock)doneBlock { - return [self queryCacheOperationForKey:key options:options done:doneBlock context:nil]; + return [self queryCacheOperationForKey:key options:options context:nil done:doneBlock]; } -- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock context:(nullable SDWebImageContext *)context { +- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context done:(nullable SDCacheQueryCompletedBlock)doneBlock { if (!key) { if (doneBlock) { doneBlock(nil, nil, SDImageCacheTypeNone); diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index c2e4df27..bfeafaae 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -11,6 +11,7 @@ typedef void(^SDWebImageNoParamsBlock)(void); typedef NSString * SDWebImageContextOption NS_STRING_ENUM; typedef NSDictionary SDWebImageContext; +typedef NSMutableDictionary SDWebImageMutableContext; #pragma mark - Image scale @@ -156,12 +157,17 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { #pragma mark - Context Options /** - A Dispatch group to maintain setImageBlock and completionBlock. This is used for custom setImageBlock advanced usage, such like perform background task but need to guarantee the completion block is called after setImageBlock. (dispatch_group_t) + A String to be used as the operation key for view category to store the image load operation. This is used for view instance which supports different image loading process. If nil, will use the class name as operation key. (NSString *) + */ +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextSetImageOperationKey; + +/** + A Dispatch group to maintain setImageBlock and completionBlock for view category. This is used for custom setImageBlock advanced usage, such like perform background task but need to guarantee the completion block is called after setImageBlock. (dispatch_group_t) */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextSetImageGroup; /** - A SDWebImageManager instance to control the image download and cache process using in UIImageView+WebCache category and likes. If not provided, use the shared manager (SDWebImageManager) + A SDWebImageManager instance to control the image download and cache process using in UIImageView+WebCache category and likes. If not provided, use the shared manager (SDWebImageManager *) */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustomManager; diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m index edb7414b..84f51da0 100644 --- a/SDWebImage/SDWebImageDefine.m +++ b/SDWebImage/SDWebImageDefine.m @@ -99,6 +99,7 @@ inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullabl #pragma mark - Context option +SDWebImageContextOption const SDWebImageContextSetImageOperationKey = @"setImageOperationKey"; SDWebImageContextOption const SDWebImageContextSetImageGroup = @"setImageGroup"; SDWebImageContextOption const SDWebImageContextCustomManager = @"customManager"; SDWebImageContextOption const SDWebImageContextCustomTransformer = @"customTransformer"; diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 7c5efe88..8f148fb8 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -254,18 +254,18 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB * * @param url The URL to the image to download * @param options The options to be used for this download + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. * @param progressBlock A block called repeatedly while the image is downloading * @note the progress block is executed on a background queue * @param completedBlock A block called once the download is completed. - * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. * * @return A token (SDWebImageDownloadToken) that can be passed to -cancel: to cancel this operation */ - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url options:(SDWebImageDownloaderOptions)options + context:(nullable SDWebImageContext *)context progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock - context:(nullable SDWebImageContext *)context; + completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock; /** * Cancels a download that was previously queued using -downloadImageWithURL:options:progress:completed: diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index ba4c6a5d..231daa2d 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -193,14 +193,14 @@ } - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock { - return [self downloadImageWithURL:url options:options progress:progressBlock completed:completedBlock context:nil]; + return [self downloadImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock]; } - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url options:(SDWebImageDownloaderOptions)options + context:(nullable SDWebImageContext *)context progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock - context:(nullable SDWebImageContext *)context { + completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock { __weak SDWebImageDownloader *wself = self; return [self addProgressCallback:progressBlock completedBlock:completedBlock forURL:url createCallback:^SDWebImageDownloaderOperation *{ diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index e5edd7dd..07ad4f23 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -180,18 +180,18 @@ SDWebImageManager.sharedManager.cacheKeyFilter = ^(NSURL * _Nullable url) { * * @param url The URL to the image * @param options A mask to specify options to use for this request + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. * @param progressBlock A block called while image is downloading * @note the progress block is executed on a background queue * @param completedBlock A block called when operation has been completed. - * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. * * @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation */ - (nullable id )loadImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nonnull SDInternalCompletionBlock)completedBlock - context:(nullable SDWebImageContext *)context; + completed:(nonnull SDInternalCompletionBlock)completedBlock; /** * Saves image to cache for given URL diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 2bc16e51..1fa92d5e 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -109,14 +109,14 @@ } - (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDInternalCompletionBlock)completedBlock { - return [self loadImageWithURL:url options:options progress:progressBlock completed:completedBlock context:nil]; + return [self loadImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock]; } - (id)loadImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nonnull SDInternalCompletionBlock)completedBlock - context:(nullable SDWebImageContext *)context { + completed:(nonnull SDInternalCompletionBlock)completedBlock { // Invoking this method without a completedBlock is pointless NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead"); @@ -165,13 +165,18 @@ } else if (self.transformer) { // Transformer from manager transformer = self.transformer; - NSMutableDictionary *mutableContext = [NSMutableDictionary dictionaryWithDictionary:context]; + SDWebImageMutableContext *mutableContext; + if (context) { + mutableContext = [context mutableCopy]; + } else { + mutableContext = [NSMutableDictionary dictionary]; + } [mutableContext setValue:transformer forKey:SDWebImageContextCustomTransformer]; context = [mutableContext copy]; } __weak SDWebImageCombinedOperation *weakOperation = operation; - operation.cacheOperation = [self.imageCache queryCacheOperationForKey:key options:cacheOptions done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) { + operation.cacheOperation = [self.imageCache queryCacheOperationForKey:key options:cacheOptions context:context done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) { __strong __typeof(weakOperation) strongOperation = weakOperation; if (!strongOperation || strongOperation.isCancelled) { [self safelyRemoveOperationFromRunning:strongOperation]; @@ -211,7 +216,7 @@ // `SDWebImageCombinedOperation` -> `SDWebImageDownloadToken` -> `downloadOperationCancelToken`, which is a `SDCallbacksDictionary` and retain the completed block below, so we need weak-strong again to avoid retain cycle __weak typeof(strongOperation) weakSubOperation = strongOperation; - strongOperation.downloadToken = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { + strongOperation.downloadToken = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions context:context progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { __strong typeof(weakSubOperation) strongSubOperation = weakSubOperation; if (!strongSubOperation || strongSubOperation.isCancelled) { // Do nothing if the operation was cancelled @@ -293,7 +298,7 @@ if (finished) { [self safelyRemoveOperationFromRunning:strongSubOperation]; } - } context:context]; + }]; } else if (cachedImage) { [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url]; [self safelyRemoveOperationFromRunning:strongOperation]; @@ -302,7 +307,7 @@ [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:nil data:nil error:nil cacheType:SDImageCacheTypeNone finished:YES url:url]; [self safelyRemoveOperationFromRunning:strongOperation]; } - } context:context]; + }]; return operation; } diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index 55713cfe..0b2d9ef3 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -86,7 +86,7 @@ NSPointerArray *operations = token.operations; for (NSURL *url in urls) { __weak typeof(self) wself = self; - id operation = [self.manager loadImageWithURL:url options:self.options progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + id operation = [self.manager loadImageWithURL:url options:self.options context:self.context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { __strong typeof(wself) sself = wself; if (!sself) { return; @@ -108,7 +108,7 @@ [sself callCompletionBlockForToken:token]; [sself removeRunningToken:token]; } - } context:self.context]; + }]; @synchronized (token) { [operations addPointer:(__bridge void *)operation]; } diff --git a/SDWebImage/UIButton+WebCache.h b/SDWebImage/UIButton+WebCache.h index ffe80651..0dea5b7a 100644 --- a/SDWebImage/UIButton+WebCache.h +++ b/SDWebImage/UIButton+WebCache.h @@ -128,6 +128,56 @@ options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock; +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + #pragma mark - Background Image /** @@ -238,6 +288,54 @@ options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock; +/** + * Set the backgroundImageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the backgroundImageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + #pragma mark - Cancel /** diff --git a/SDWebImage/UIButton+WebCache.m b/SDWebImage/UIButton+WebCache.m index 8cdadb67..9df79587 100644 --- a/SDWebImage/UIButton+WebCache.m +++ b/SDWebImage/UIButton+WebCache.m @@ -72,10 +72,20 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:completedBlock]; } +- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:options progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; +} + - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { if (!url) { [self.sd_imageURLStorage removeObjectForKey:imageURLKeyForState(state)]; @@ -83,16 +93,27 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat self.sd_imageURLStorage[imageURLKeyForState(state)] = url; } + SDWebImageMutableContext *mutableContext; + if (context) { + mutableContext = [context mutableCopy]; + } else { + mutableContext = [NSMutableDictionary dictionary]; + } + mutableContext[SDWebImageContextSetImageOperationKey] = imageOperationKeyForState(state); __weak typeof(self)weakSelf = self; [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options - operationKey:imageOperationKeyForState(state) + context:mutableContext setImageBlock:^(UIImage *image, NSData *imageData) { [weakSelf setImage:image forState:state]; } - progress:nil - completed:completedBlock]; + progress:progressBlock + completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType, imageURL); + } + }]; } #pragma mark - Background Image @@ -131,10 +152,20 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:completedBlock]; } +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 context:nil progress:progressBlock completed:completedBlock]; +} + - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { if (!url) { [self.sd_imageURLStorage removeObjectForKey:backgroundImageURLKeyForState(state)]; @@ -142,16 +173,27 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat self.sd_imageURLStorage[backgroundImageURLKeyForState(state)] = url; } + SDWebImageMutableContext *mutableContext; + if (context) { + mutableContext = [context mutableCopy]; + } else { + mutableContext = [NSMutableDictionary dictionary]; + } + mutableContext[SDWebImageContextSetImageOperationKey] = imageOperationKeyForState(state); __weak typeof(self)weakSelf = self; [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options - operationKey:backgroundImageOperationKeyForState(state) + context:mutableContext setImageBlock:^(UIImage *image, NSData *imageData) { [weakSelf setBackgroundImage:image forState:state]; } - progress:nil - completed:completedBlock]; + progress:progressBlock + completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType, imageURL); + } + }]; } #pragma mark - Cancel diff --git a/SDWebImage/UIImageView+HighlightedWebCache.m b/SDWebImage/UIImageView+HighlightedWebCache.m index fb13bd8b..e4dd3a51 100644 --- a/SDWebImage/UIImageView+HighlightedWebCache.m +++ b/SDWebImage/UIImageView+HighlightedWebCache.m @@ -13,6 +13,8 @@ #import "UIView+WebCacheOperation.h" #import "UIView+WebCache.h" +static NSString * const SDHighlightedImageOperationKey = @"UIImageViewImageOperationHighlighted"; + @implementation UIImageView (HighlightedWebCache) - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url { @@ -31,20 +33,36 @@ [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:completedBlock]; } +- (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDExternalCompletionBlock)completedBlock { + [self sd_setHighlightedImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock]; +} + - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { __weak typeof(self)weakSelf = self; + SDWebImageMutableContext *mutableContext; + if (context) { + mutableContext = [context mutableCopy]; + } else { + mutableContext = [NSMutableDictionary dictionary]; + } + mutableContext[SDWebImageContextSetImageOperationKey] = SDHighlightedImageOperationKey; [self sd_internalSetImageWithURL:url placeholderImage:nil options:options - operationKey:@"UIImageViewImageOperationHighlighted" + context:mutableContext setImageBlock:^(UIImage *image, NSData *imageData) { weakSelf.highlightedImage = image; } progress:progressBlock - completed:completedBlock]; + completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType, imageURL); + } + }]; } @end diff --git a/SDWebImage/UIImageView+WebCache.h b/SDWebImage/UIImageView+WebCache.h index 7b7d530d..204c2278 100644 --- a/SDWebImage/UIImageView+WebCache.h +++ b/SDWebImage/UIImageView+WebCache.h @@ -154,6 +154,30 @@ progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + #if SD_UIKIT #pragma mark - Animation of multiple images diff --git a/SDWebImage/UIImageView+WebCache.m b/SDWebImage/UIImageView+WebCache.m index cc9b476d..31bcabb9 100644 --- a/SDWebImage/UIImageView+WebCache.m +++ b/SDWebImage/UIImageView+WebCache.m @@ -40,18 +40,27 @@ [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; } +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; +} + - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options - operationKey:nil + context:context setImageBlock:nil progress:progressBlock - completed:completedBlock]; + completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + if (completedBlock) { + completedBlock(image, error, cacheType, imageURL); + } + }]; } #if SD_UIKIT diff --git a/SDWebImage/UIView+WebCache.h b/SDWebImage/UIView+WebCache.h index 593e6be3..a5f1046f 100644 --- a/SDWebImage/UIView+WebCache.h +++ b/SDWebImage/UIView+WebCache.h @@ -48,51 +48,29 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima * @param url The url for the image. * @param placeholder The image to be set initially, until the image request finishes. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. - * @param operationKey A string to be used as the operation key. If nil, will use the class name - * @param setImageBlock Block used for custom set image code - * @param progressBlock A block called while image is downloading - * @note the progress block is executed on a background queue - * @param completedBlock A block called when operation has been completed. This block has no return value - * and takes the requested UIImage as first parameter. In case of error the image parameter - * is nil and the second parameter may contain an NSError. The third parameter is a Boolean - * indicating if the image was retrieved from the local cache or from the network. - * The fourth parameter is the original image url. - */ -- (void)sd_internalSetImageWithURL:(nullable NSURL *)url - placeholderImage:(nullable UIImage *)placeholder - options:(SDWebImageOptions)options - operationKey:(nullable NSString *)operationKey - setImageBlock:(nullable SDSetImageBlock)setImageBlock - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDExternalCompletionBlock)completedBlock; - -/** - * Set the imageView `image` with an `url` and optionally a placeholder image. - * - * The download is asynchronous and cached. - * - * @param url The url for the image. - * @param placeholder The image to be set initially, until the image request finishes. - * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. - * @param operationKey A string to be used as the operation key. If nil, will use the class name - * @param setImageBlock Block used for custom set image code - * @param progressBlock A block called while image is downloading - * @note the progress block is executed on a background queue - * @param completedBlock A block called when operation has been completed. This block has no return value - * and takes the requested UIImage as first parameter. In case of error the image parameter - * is nil and the second parameter may contain an NSError. The third parameter is a Boolean - * indicating if the image was retrieved from the local cache or from the network. - * The fourth parameter is the original image url. * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * @param setImageBlock Block used for custom set image code. If not provide, use the built-in set image code (supports `UIImageView/NSImageView` and `UIButton/NSButton` currently) + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. + * This block has no return value and takes the requested UIImage as first parameter and the NSData representation as second parameter. + * In case of error the image parameter is nil and the third parameter may contain an NSError. + * + * The forth parameter is an `SDImageCacheType` enum indicating if the image was retrieved from the local cache + * or from the memory cache or from the network. + * + * The fith parameter normally is always YES. However, if you provide SDWebImageAvoidAutoSetImage with SDWebImageProgressiveDownload options to enable progressive downloading and set the image yourself. This block is thus called repeatedly with a partial image. When image is fully downloaded, the + * block is called a last time with the full image and the last parameter set to YES. + * + * The last parameter is the original image URL */ - (void)sd_internalSetImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - operationKey:(nullable NSString *)operationKey + context:(nullable SDWebImageContext *)context setImageBlock:(nullable SDSetImageBlock)setImageBlock progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDExternalCompletionBlock)completedBlock - context:(nullable SDWebImageContext *)context; + completed:(nullable SDInternalCompletionBlock)completedBlock; /** * Cancel the current image load diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 3ab40e82..921d1017 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -15,16 +15,14 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; -static char imageURLKey; - @implementation UIView (WebCache) - (nullable NSURL *)sd_imageURL { - return objc_getAssociatedObject(self, &imageURLKey); + return objc_getAssociatedObject(self, @selector(sd_imageURL)); } - (void)setSd_imageURL:(NSURL * _Nullable)sd_imageURL { - objc_setAssociatedObject(self, &imageURLKey, sd_imageURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(self, @selector(sd_imageURL), sd_imageURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSProgress *)sd_imageProgress { @@ -43,28 +41,31 @@ static char imageURLKey; - (void)sd_internalSetImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - operationKey:(nullable NSString *)operationKey - setImageBlock:(nullable SDSetImageBlock)setImageBlock - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDExternalCompletionBlock)completedBlock { - return [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options operationKey:operationKey setImageBlock:setImageBlock progress:progressBlock completed:completedBlock context:nil]; -} - -- (void)sd_internalSetImageWithURL:(nullable NSURL *)url - placeholderImage:(nullable UIImage *)placeholder - options:(SDWebImageOptions)options - operationKey:(nullable NSString *)operationKey - setImageBlock:(nullable SDSetImageBlock)setImageBlock - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDExternalCompletionBlock)completedBlock - context:(nullable SDWebImageContext *)context { - NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]); + context:(nullable SDWebImageContext *)context + setImageBlock:(nullable SDSetImageBlock)setImageBlock progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDInternalCompletionBlock)completedBlock { + context = [context copy]; // copy to avoid mutable object + NSString *validOperationKey = nil; + if ([context valueForKey:SDWebImageContextSetImageOperationKey]) { + validOperationKey = [context valueForKey:SDWebImageContextSetImageOperationKey]; + } else { + validOperationKey = NSStringFromClass([self class]); + } + dispatch_group_t group = nil; + if ([context valueForKey:SDWebImageContextSetImageGroup]) { + group = [context valueForKey:SDWebImageContextSetImageGroup]; + } + if (context && group) { + // Remove the context option for View Category only and pass others for manager + // Operation key may be useful for some advanced feature, keep it + SDWebImageMutableContext *mutableContext = [context mutableCopy]; + [mutableContext removeObjectForKey:SDWebImageContextSetImageGroup]; + context = [mutableContext copy]; + } [self sd_cancelImageLoadOperationWithKey:validOperationKey]; self.sd_imageURL = url; if (!(options & SDWebImageDelayPlaceholder)) { - if ([context valueForKey:SDWebImageContextSetImageGroup]) { - dispatch_group_t group = [context valueForKey:SDWebImageContextSetImageGroup]; + if (group) { dispatch_group_enter(group); } dispatch_main_async_safe(^{ @@ -103,7 +104,7 @@ static char imageURLKey; }); } }; - id operation = [manager loadImageWithURL:url options:options progress:combinedProgressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + id operation = [manager loadImageWithURL:url options:options context:context progress:combinedProgressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { __strong __typeof (wself) sself = wself; if (!sself) { return; } // if the progress not been updated, mark it to complete state @@ -126,7 +127,7 @@ static char imageURLKey; [sself sd_setNeedsLayout]; } if (completedBlock && shouldCallCompletedBlock) { - completedBlock(image, error, cacheType, url); + completedBlock(image, data, error, cacheType, finished, url); } }; @@ -156,8 +157,7 @@ static char imageURLKey; transition = sself.sd_imageTransition; } - if ([context valueForKey:SDWebImageContextSetImageGroup]) { - dispatch_group_t group = [context valueForKey:SDWebImageContextSetImageGroup]; + if (group) { dispatch_group_enter(group); dispatch_main_async_safe(^{ [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL]; @@ -172,14 +172,14 @@ static char imageURLKey; callCompletedBlockClojure(); }); } - } context:context]; + }]; [self sd_setImageLoadOperation:operation forKey:validOperationKey]; } else { [self sd_stopImageIndicator]; dispatch_main_async_safe(^{ if (completedBlock) { NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; - completedBlock(nil, error, SDImageCacheTypeNone, url); + completedBlock(nil, nil, error, YES, SDImageCacheTypeNone, url); } }); } @@ -215,6 +215,14 @@ static char imageURLKey; }; } #endif +#if SD_MAC + else if ([view isKindOfClass:[NSButton class]]) { + NSButton *button = (NSButton *)view; + finalSetImageBlock = ^(UIImage *setImage, NSData *setImageData){ + button.image = setImage; + }; + } +#endif if (transition) { #if SD_UIKIT diff --git a/Tests/Tests/SDWebCacheCategoriesTests.m b/Tests/Tests/SDWebCacheCategoriesTests.m index c22c1686..3d1b5d48 100644 --- a/Tests/Tests/SDWebCacheCategoriesTests.m +++ b/Tests/Tests/SDWebCacheCategoriesTests.m @@ -160,7 +160,7 @@ // Clear the disk cache to force download from network [[SDImageCache sharedImageCache] removeImageForKey:kTestJpegURL withCompletion:^{ - [view sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 operationKey:nil setImageBlock:nil progress:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { + [view sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 context:nil progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { expect(view.sd_imageProgress.fractionCompleted).equal(1.0); expect([view.sd_imageProgress.userInfo[NSStringFromSelector(_cmd)] boolValue]).equal(YES); [expectation fulfill]; From c21381e83be2e332f48e160800e46aff17c32b05 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 2 Apr 2018 22:28:45 +0800 Subject: [PATCH 084/361] Change `isRunning` on manager from method to property --- SDWebImage/SDWebImageManager.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 07ad4f23..c78779bd 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -134,6 +134,11 @@ SDWebImageManager.sharedManager.cacheKeyFilter = ^(NSURL * _Nullable url) { */ @property (nonatomic, copy, nullable) SDWebImageCacheSerializerBlock cacheSerializer; +/** + * Check one or more operations running + */ +@property (nonatomic, assign, readonly, getter=isRunning) BOOL running; + /** * Returns global shared manager instance. */ @@ -208,11 +213,6 @@ SDWebImageManager.sharedManager.cacheKeyFilter = ^(NSURL * _Nullable url) { */ - (void)cancelAll; -/** - * Check one or more operations running - */ -- (BOOL)isRunning; - /** * Async check if image has already been cached * From 6bdcf632243be93135cf7f671a068b7b8c331b06 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 3 Apr 2018 02:07:59 +0800 Subject: [PATCH 085/361] Fix the test build --- Tests/Tests/SDWebCacheCategoriesTests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Tests/SDWebCacheCategoriesTests.m b/Tests/Tests/SDWebCacheCategoriesTests.m index 3d1b5d48..d10c1765 100644 --- a/Tests/Tests/SDWebCacheCategoriesTests.m +++ b/Tests/Tests/SDWebCacheCategoriesTests.m @@ -160,7 +160,7 @@ // Clear the disk cache to force download from network [[SDImageCache sharedImageCache] removeImageForKey:kTestJpegURL withCompletion:^{ - [view sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 context:nil progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + [view sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 context:nil setImageBlock:nil progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { expect(view.sd_imageProgress.fractionCompleted).equal(1.0); expect([view.sd_imageProgress.userInfo[NSStringFromSelector(_cmd)] boolValue]).equal(YES); [expectation fulfill]; From c3892d7d082ec7730fa9dcf1669bb0da3aeae798 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 31 Mar 2018 05:34:10 +0800 Subject: [PATCH 086/361] Move all download settings into SDWebImageDownloaderConfig, make it more easy to use with clear API. Deprecate `createNewSessionWithConfiguration`, which make downloader not sync with URLSession. If user need to specify sharedDownloader config, just modify the defaultDownloaderConfig instead. --- .../SDWebImage Demo/MasterViewController.m | 6 +- SDWebImage.xcodeproj/project.pbxproj | 28 +++++ SDWebImage/SDWebImageDownloader.h | 113 ++++-------------- SDWebImage/SDWebImageDownloader.m | 106 +++++++--------- SDWebImage/SDWebImageDownloaderConfig.h | 81 +++++++++++++ SDWebImage/SDWebImageDownloaderConfig.m | 55 +++++++++ SDWebImage/SDWebImageDownloaderOperation.h | 4 +- Tests/Tests/SDWebImageDownloaderTests.m | 30 ++--- WebImage/SDWebImage.h | 1 + 9 files changed, 256 insertions(+), 168 deletions(-) create mode 100644 SDWebImage/SDWebImageDownloaderConfig.h create mode 100644 SDWebImage/SDWebImageDownloaderConfig.m diff --git a/Examples/SDWebImage Demo/MasterViewController.m b/Examples/SDWebImage Demo/MasterViewController.m index 9def6051..58469d2a 100644 --- a/Examples/SDWebImage Demo/MasterViewController.m +++ b/Examples/SDWebImage Demo/MasterViewController.m @@ -56,8 +56,8 @@ // HTTP NTLM auth example // Add your NTLM image url to the array below and replace the credentials - [SDWebImageManager sharedManager].imageDownloader.username = @"httpwatch"; - [SDWebImageManager sharedManager].imageDownloader.password = @"httpwatch01"; + [SDWebImageManager sharedManager].imageDownloader.config.username = @"httpwatch"; + [SDWebImageManager sharedManager].imageDownloader.config.password = @"httpwatch01"; self.objects = [NSMutableArray arrayWithObjects: @"http://www.httpwatch.com/httpgallery/authentication/authenticatedimage/default.aspx?0.35786508303135633", // requires HTTP auth, used to demo the NTLM auth @@ -79,7 +79,7 @@ } [SDWebImageManager.sharedManager.imageDownloader setValue:@"SDWebImage Demo" forHTTPHeaderField:@"AppName"]; - SDWebImageManager.sharedManager.imageDownloader.executionOrder = SDWebImageDownloaderLIFOExecutionOrder; + SDWebImageManager.sharedManager.imageDownloader.config.executionOrder = SDWebImageDownloaderLIFOExecutionOrder; return self; } diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index c17c2136..4760c2d7 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -412,6 +412,18 @@ 329A18621FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; 329A18631FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; 329A18641FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; + 32B9B537206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32B9B538206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32B9B53A206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32B9B53B206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32B9B53C206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32B9B53D206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */; }; + 32B9B53E206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */; }; + 32B9B53F206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */; }; + 32B9B540206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */; }; + 32B9B541206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */; }; + 32B9B542206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */; }; 32C0FDE12013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32C0FDE22013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32C0FDE32013426C001B8F2D /* SDWebImageIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1472,6 +1484,8 @@ 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageFrame.m; sourceTree = ""; }; 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImage+WebCache.h"; path = "SDWebImage/UIImage+WebCache.h"; sourceTree = ""; }; 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImage+WebCache.m"; path = "SDWebImage/UIImage+WebCache.m"; sourceTree = ""; }; + 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderConfig.h; sourceTree = ""; }; + 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderConfig.m; sourceTree = ""; }; 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageIndicator.h; sourceTree = ""; }; 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageIndicator.m; sourceTree = ""; }; 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoderHelper.h; sourceTree = ""; }; @@ -1968,6 +1982,8 @@ 53922D8C148C56230056699D /* SDWebImageDownloader.m */, 530E49E316460AE2002868E7 /* SDWebImageDownloaderOperation.h */, 530E49E416460AE2002868E7 /* SDWebImageDownloaderOperation.m */, + 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */, + 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */, ); name = Downloader; sourceTree = ""; @@ -2174,6 +2190,7 @@ 323F8B531F38EF770092B609 /* backward_references_enc.h in Headers */, 4317395A1CDFC8B70008FEB9 /* mux_types.h in Headers */, 431739561CDFC8B70008FEB9 /* demux.h in Headers */, + 32B9B53A206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 80377C4A1F2F666300F89830 /* bit_writer_utils.h in Headers */, 4397D2F81D0DF44200BB2784 /* MKAnnotationView+WebCache.h in Headers */, 323F8BE71F38EF770092B609 /* vp8li_enc.h in Headers */, @@ -2264,6 +2281,7 @@ 321E60B11F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 80377E9A1F2F66D400F89830 /* common_dec.h in Headers */, 327054D5206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, + 32B9B538206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 80377C231F2F666300F89830 /* quant_levels_utils.h in Headers */, 321E60BF1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 80377EA61F2F66D400F89830 /* webpi_dec.h in Headers */, @@ -2405,6 +2423,7 @@ 43A62A201D0E0A800089D7DD /* mux_types.h in Headers */, 43A62A211D0E0A800089D7DD /* types.h in Headers */, 80377C641F2F666400F89830 /* bit_writer_utils.h in Headers */, + 32B9B53B206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 43A62A1E1D0E0A800089D7DD /* format_constants.h in Headers */, 80377E111F2F66A800F89830 /* lossless_common.h in Headers */, 431BB6F61D06D2C1006A3455 /* UIImage+MultiFormat.h in Headers */, @@ -2435,6 +2454,7 @@ 32F7C0892030719600873181 /* UIImage+Transform.h in Headers */, 80377EDA1F2F66D500F89830 /* common_dec.h in Headers */, 80377EE61F2F66D500F89830 /* webpi_dec.h in Headers */, + 32B9B53C206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 4397D2BA1D0DDD8C00BB2784 /* demux.h in Headers */, 80377C8F1F2F666400F89830 /* rescaler_utils.h in Headers */, 4397D2BD1D0DDD8C00BB2784 /* types.h in Headers */, @@ -2525,6 +2545,7 @@ 323F8B521F38EF770092B609 /* backward_references_enc.h in Headers */, 4317394F1CDFC8B70008FEB9 /* demux.h in Headers */, 43CE757D1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, + 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 80377C301F2F666300F89830 /* bit_writer_utils.h in Headers */, 431739541CDFC8B70008FEB9 /* types.h in Headers */, 323F8BE61F38EF770092B609 /* vp8li_enc.h in Headers */, @@ -2631,6 +2652,7 @@ 80377D1D1F2F66A100F89830 /* yuv.h in Headers */, 43CE75D01CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */, 807A12281F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, + 32B9B537206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 80377C051F2F665300F89830 /* huffman_utils.h in Headers */, 80377E881F2F66D000F89830 /* alphai_dec.h in Headers */, 32484775201775F600AF9E5A /* SDAnimatedImage.h in Headers */, @@ -2993,6 +3015,7 @@ 80377EBE1F2F66D500F89830 /* quant_dec.c in Sources */, 80377DB61F2F66A700F89830 /* dec_clip_tables.c in Sources */, 80377C5E1F2F666300F89830 /* utils.c in Sources */, + 32B9B540206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, 323F8C0B1F38EF770092B609 /* muxedit.c in Sources */, 80377DC11F2F66A700F89830 /* enc_mips32.c in Sources */, 80377DBC1F2F66A700F89830 /* dec_sse41.c in Sources */, @@ -3172,6 +3195,7 @@ 3237F9EC20161AE000A88143 /* NSImage+Additions.m in Sources */, 4314D1411D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.m in Sources */, 80377D561F2F66A700F89830 /* rescaler_neon.c in Sources */, + 32B9B53E206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, 32F7C0762030114C00873181 /* SDWebImageTransformer.m in Sources */, 80377D551F2F66A700F89830 /* rescaler_msa.c in Sources */, 80377D5E1F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */, @@ -3327,6 +3351,7 @@ 3237F9EA20161AE000A88143 /* NSImage+Additions.m in Sources */, 431BB6B61D06D2C1006A3455 /* UIImage+WebP.m in Sources */, 80377E251F2F66A800F89830 /* rescaler_neon.c in Sources */, + 32B9B541206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, 32F7C0792030114C00873181 /* SDWebImageTransformer.m in Sources */, 80377E241F2F66A800F89830 /* rescaler_msa.c in Sources */, 80377E2D1F2F66A800F89830 /* yuv_mips_dsp_r2.c in Sources */, @@ -3411,6 +3436,7 @@ 3290FA0F1FA478AF0047D20C /* SDWebImageFrame.m in Sources */, 80377EE01F2F66D500F89830 /* vp8_dec.c in Sources */, 32CF1C121FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */, + 32B9B542206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, 80377E521F2F66A800F89830 /* filters_msa.c in Sources */, 329A18641FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, 80377C821F2F666400F89830 /* filters_utils.c in Sources */, @@ -3619,6 +3645,7 @@ 80377EAE1F2F66D400F89830 /* quant_dec.c in Sources */, 80377D6E1F2F66A700F89830 /* cost_sse2.c in Sources */, 80377D991F2F66A700F89830 /* rescaler_mips32.c in Sources */, + 32B9B53F206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, 323F8C0A1F38EF770092B609 /* muxedit.c in Sources */, 80377D851F2F66A700F89830 /* filters_sse2.c in Sources */, 80377D711F2F66A700F89830 /* dec_clip_tables.c in Sources */, @@ -3778,6 +3805,7 @@ 80377CE41F2F66A100F89830 /* cost_sse2.c in Sources */, 80377D0F1F2F66A100F89830 /* rescaler_mips32.c in Sources */, 323F8C081F38EF770092B609 /* muxedit.c in Sources */, + 32B9B53D206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, 80377CFB1F2F66A100F89830 /* filters_sse2.c in Sources */, 80377CE71F2F66A100F89830 /* dec_clip_tables.c in Sources */, 43A9186B1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 8f148fb8..3690986d 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -10,6 +10,7 @@ #import "SDWebImageCompat.h" #import "SDWebImageDefine.h" #import "SDWebImageOperation.h" +#import "SDWebImageDownloaderConfig.h" typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { /** @@ -73,18 +74,6 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { SDWebImageDownloaderPreloadAllFrames = 1 << 10 }; -typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { - /** - * Default value. All download operations will execute in queue style (first-in-first-out). - */ - SDWebImageDownloaderFIFOExecutionOrder, - - /** - * All download operations will execute in stack style (last-in-first-out). - */ - SDWebImageDownloaderLIFOExecutionOrder -}; - FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStartNotification; FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStopNotification; @@ -121,67 +110,9 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB @interface SDWebImageDownloader : NSObject /** - * Decompressing images that are downloaded and cached can improve performance but can consume lot of memory. - * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. + Downloader Config object - storing all kind of settings */ -@property (assign, nonatomic) BOOL shouldDecompressImages; - -/** - * The maximum number of concurrent downloads - */ -@property (assign, nonatomic) NSInteger maxConcurrentDownloads; - -/** - * Shows the current amount of downloads that still need to be downloaded - */ -@property (readonly, nonatomic) NSUInteger currentDownloadCount; - -/** - * The timeout value (in seconds) for the download operation. Default: 15.0. - */ -@property (assign, nonatomic) NSTimeInterval downloadTimeout; - -/** - * The configuration in use by the internal NSURLSession. - * Mutating this object directly has no effect. - * - * @see createNewSessionWithConfiguration: - */ -@property (readonly, nonatomic, nonnull) NSURLSessionConfiguration *sessionConfiguration; - -/** - * Gets/Sets a subclass of `SDWebImageDownloaderOperation` as the default - * `NSOperation` to be used each time SDWebImage constructs a request - * operation to download an image. - * - * @note Passing `NSOperation` to set as default. Passing `nil` will revert to `SDWebImageDownloaderOperation`. - */ -@property (assign, nonatomic, nullable) Class operationClass; - -/** - * Gets/Sets the download queue suspension state. - */ -@property (assign, nonatomic, getter=isSuspended) BOOL suspended; - -/** - * Changes download operations execution order. Default value is `SDWebImageDownloaderFIFOExecutionOrder`. - */ -@property (assign, nonatomic) SDWebImageDownloaderExecutionOrder executionOrder; - -/** - * Set the default URL credential to be set for request operations. - */ -@property (strong, nonatomic, nullable) NSURLCredential *urlCredential; - -/** - * Set username - */ -@property (strong, nonatomic, nullable) NSString *username; - -/** - * Set password - */ -@property (strong, nonatomic, nullable) NSString *password; +@property (nonatomic, copy, readonly, nonnull) SDWebImageDownloaderConfig *config; /** * Set filter to pick headers for downloading image HTTP request. @@ -192,16 +123,34 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB @property (nonatomic, copy, nullable) SDWebImageDownloaderHeadersFilterBlock headersFilter; /** - * Returns the global shared downloader instance + * The configuration in use by the internal NSURLSession. If you want to provide a custom sessionConfiguration, use `SDWebImageDownloaderConfig.sessionConfiguration` and create a new downloader instance. + @note This is immutable according to NSURLSession's documentation. Mutating this object directly has no effect. + */ +@property (nonatomic, readonly, nonnull) NSURLSessionConfiguration *sessionConfiguration; + +/** + * Gets/Sets the download queue suspension state. + */ +@property (nonatomic, assign, getter=isSuspended) BOOL suspended; + +/** + * Shows the current amount of downloads that still need to be downloaded + */ +@property (nonatomic, assign, readonly) NSUInteger currentDownloadCount; + +/** + * Returns the global shared downloader instance. Which use the `SDWebImageDownloaderConfig.defaultDownloaderConfiguration` config. */ @property (nonatomic, class, readonly, nonnull) SDWebImageDownloader *sharedDownloader; /** - * Creates an instance of a downloader with specified session configuration. - * @note `timeoutIntervalForRequest` is going to be overwritten. - * @return new instance of downloader class + Creates an instance of a downloader with specified downloader config. + You can specify session configuration, timeout or operation class through downloader config. + + @param config The downloader config. If you specify nil, the `defaultDownloaderConfig` will be used. + @return new instance of downloader class */ -- (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration NS_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithConfig:(nullable SDWebImageDownloaderConfig *)config NS_DESIGNATED_INITIALIZER; /** * Set a value for a HTTP header to be appended to each download HTTP request. @@ -279,16 +228,6 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB */ - (void)cancelAllDownloads; -/** - * Forces SDWebImageDownloader to create and use a new NSURLSession that is - * initialized with the given configuration. - * @note All existing download operations in the queue will be cancelled. - * @note `timeoutIntervalForRequest` is going to be overwritten. - * - * @param sessionConfiguration The configuration to use for the new NSURLSession - */ -- (void)createNewSessionWithConfiguration:(nonnull NSURLSessionConfiguration *)sessionConfiguration; - /** * Invalidates the managed session, optionally canceling pending operations. * @note If you use custom downloader instead of the shared downloader, you need call this method when you do not use it to avoid memory leak diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 231daa2d..050f60b0 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -7,6 +7,7 @@ */ #import "SDWebImageDownloader.h" +#import "SDWebImageDownloaderConfig.h" #import "SDWebImageDownloaderOperation.h" #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); @@ -14,7 +15,7 @@ @interface SDWebImageDownloadToken () -@property (nonatomic, weak, nullable) NSOperation *downloadOperation; +@property (nonatomic, weak, nullable) NSOperation *downloadOperation; @end @@ -81,14 +82,16 @@ } - (nonnull instancetype)init { - return [self initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; + return [self initWithConfig:SDWebImageDownloaderConfig.defaultDownloaderConfig]; } -- (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration { - if ((self = [super init])) { - _operationClass = [SDWebImageDownloaderOperation class]; - _shouldDecompressImages = YES; - _executionOrder = SDWebImageDownloaderFIFOExecutionOrder; +- (instancetype)initWithConfig:(SDWebImageDownloaderConfig *)config { + self = [super init]; + if (self) { + if (!config) { + config = SDWebImageDownloaderConfig.defaultDownloaderConfig; + } + _config = [config copy]; _downloadQueue = [NSOperationQueue new]; _downloadQueue.maxConcurrentOperationCount = 6; _downloadQueue.name = @"com.hackemist.SDWebImageDownloader"; @@ -100,30 +103,21 @@ #endif _operationsLock = dispatch_semaphore_create(1); _headersLock = dispatch_semaphore_create(1); - _downloadTimeout = 15.0; - - [self createNewSessionWithConfiguration:sessionConfiguration]; - } - return self; -} - -- (void)createNewSessionWithConfiguration:(NSURLSessionConfiguration *)sessionConfiguration { - [self cancelAllDownloads]; - - if (self.session) { - [self.session invalidateAndCancel]; - } - - sessionConfiguration.timeoutIntervalForRequest = self.downloadTimeout; - - /** - * Create the session for this task - * We send nil as delegate queue so that the session creates a serial operation queue for performing all delegate - * method calls and completion handler calls. - */ - self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration + NSURLSessionConfiguration *sessionConfiguration = _config.sessionConfiguration; + if (!sessionConfiguration) { + sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; + } + sessionConfiguration.timeoutIntervalForRequest = _config.downloadTimeout; + /** + * Create the session for this task + * We send nil as delegate queue so that the session creates a serial operation queue for performing all delegate + * method calls and completion handler calls. + */ + _session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil]; + } + return self; } - (void)invalidateSessionAndCancel:(BOOL)cancelPendingOperations { @@ -144,6 +138,10 @@ [self.downloadQueue cancelAllOperations]; } +- (NSURLSessionConfiguration *)sessionConfiguration { + return self.session.configuration; +} + - (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field { LOCK(self.headersLock); if (value) { @@ -168,30 +166,6 @@ return allHTTPHeaderFields; } -- (void)setMaxConcurrentDownloads:(NSInteger)maxConcurrentDownloads { - _downloadQueue.maxConcurrentOperationCount = maxConcurrentDownloads; -} - -- (NSUInteger)currentDownloadCount { - return _downloadQueue.operationCount; -} - -- (NSInteger)maxConcurrentDownloads { - return _downloadQueue.maxConcurrentOperationCount; -} - -- (NSURLSessionConfiguration *)sessionConfiguration { - return self.session.configuration; -} - -- (void)setOperationClass:(nullable Class)operationClass { - if (operationClass && [operationClass isSubclassOfClass:[NSOperation class]] && [operationClass conformsToProtocol:@protocol(SDWebImageDownloaderOperationInterface)]) { - _operationClass = operationClass; - } else { - _operationClass = [SDWebImageDownloaderOperation class]; - } -} - - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock { return [self downloadImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock]; } @@ -205,7 +179,7 @@ return [self addProgressCallback:progressBlock completedBlock:completedBlock forURL:url createCallback:^SDWebImageDownloaderOperation *{ __strong __typeof (wself) sself = wself; - NSTimeInterval timeoutInterval = sself.downloadTimeout; + NSTimeInterval timeoutInterval = sself.config.downloadTimeout; if (timeoutInterval == 0.0) { timeoutInterval = 15.0; } @@ -224,13 +198,19 @@ else { request.allHTTPHeaderFields = [sself allHTTPHeaderFields]; } - SDWebImageDownloaderOperation *operation = [[sself.operationClass alloc] initWithRequest:request inSession:sself.session options:options context:context]; - operation.shouldDecompressImages = sself.shouldDecompressImages; + Class operationClass = sself.config.operationClass; + if (operationClass && [operationClass isSubclassOfClass:[NSOperation class]] && [operationClass conformsToProtocol:@protocol(SDWebImageDownloaderOperation)]) { + // Custom operation class + } else { + operationClass = [SDWebImageDownloaderOperation class]; + } + SDWebImageDownloaderOperation *operation = [[operationClass alloc] initWithRequest:request inSession:sself.session options:options context:context]; + operation.shouldDecompressImages = sself.config.shouldDecompressImages; - if (sself.urlCredential) { - operation.credential = sself.urlCredential; - } else if (sself.username && sself.password) { - operation.credential = [NSURLCredential credentialWithUser:sself.username password:sself.password persistence:NSURLCredentialPersistenceForSession]; + if (sself.config.urlCredential) { + operation.credential = sself.config.urlCredential; + } else if (sself.config.username && sself.config.password) { + operation.credential = [NSURLCredential credentialWithUser:sself.config.username password:sself.config.password persistence:NSURLCredentialPersistenceForSession]; } if (options & SDWebImageDownloaderHighPriority) { @@ -239,7 +219,7 @@ operation.queuePriority = NSOperationQueuePriorityLow; } - if (sself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) { + if (sself.config.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) { // Emulate LIFO execution order by systematically adding new operations as last operation's dependency [sself.lastAddedOperation addDependency:operation]; sself.lastAddedOperation = operation; @@ -316,6 +296,10 @@ self.downloadQueue.suspended = suspended; } +- (NSUInteger)currentDownloadCount { + return self.downloadQueue.operationCount; +} + - (void)cancelAllDownloads { [self.downloadQueue cancelAllOperations]; } diff --git a/SDWebImage/SDWebImageDownloaderConfig.h b/SDWebImage/SDWebImageDownloaderConfig.h new file mode 100644 index 00000000..1b3b52e8 --- /dev/null +++ b/SDWebImage/SDWebImageDownloaderConfig.h @@ -0,0 +1,81 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" + +typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { + /** + * Default value. All download operations will execute in queue style (first-in-first-out). + */ + SDWebImageDownloaderFIFOExecutionOrder, + + /** + * All download operations will execute in stack style (last-in-first-out). + */ + SDWebImageDownloaderLIFOExecutionOrder +}; + +@interface SDWebImageDownloaderConfig : NSObject + +/** + Gets/Sets the default downloader config. + */ +@property (nonatomic, class, nonnull) SDWebImageDownloaderConfig *defaultDownloaderConfig; + +/** + * Decompressing images that are downloaded and cached can improve performance but can consume lot of memory. + * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. + */ +@property (nonatomic, assign) BOOL shouldDecompressImages; + +/** + * The maximum number of concurrent downloads + */ +@property (nonatomic, assign) NSInteger maxConcurrentDownloads; + +/** + * The timeout value (in seconds) for the download operation. Default: 15.0. + */ +@property (nonatomic, assign) NSTimeInterval downloadTimeout; + +/** + * The custom session configuration in use by NSURLSession. + */ +@property (nonatomic, strong, nonnull) NSURLSessionConfiguration *sessionConfiguration; + +/** + * Gets/Sets a subclass of `SDWebImageDownloaderOperation` as the default + * `NSOperation` to be used each time SDWebImage constructs a request + * operation to download an image. + * + * @note Passing `NSOperation` to set as default. Passing `nil` will revert to `SDWebImageDownloaderOperation`. + */ +@property (nonatomic, assign, nullable) Class operationClass; + +/** + * Changes download operations execution order. Default value is `SDWebImageDownloaderFIFOExecutionOrder`. + */ +@property (nonatomic, assign) SDWebImageDownloaderExecutionOrder executionOrder; + +/** + * Set the default URL credential to be set for request operations. + */ +@property (nonatomic, strong, nullable) NSURLCredential *urlCredential; + +/** + * Set username + */ +@property (nonatomic, copy, nullable) NSString *username; + +/** + * Set password + */ +@property (nonatomic, copy, nullable) NSString *password; + +@end diff --git a/SDWebImage/SDWebImageDownloaderConfig.m b/SDWebImage/SDWebImageDownloaderConfig.m new file mode 100644 index 00000000..2783af14 --- /dev/null +++ b/SDWebImage/SDWebImageDownloaderConfig.m @@ -0,0 +1,55 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageDownloaderConfig.h" + +static SDWebImageDownloaderConfig * _defaultDownloaderConfig; + +@implementation SDWebImageDownloaderConfig + ++ (SDWebImageDownloaderConfig *)defaultDownloaderConfig { + if (!_defaultDownloaderConfig) { + _defaultDownloaderConfig = [SDWebImageDownloaderConfig new]; + } + return _defaultDownloaderConfig; +} + ++ (void)setDefaultDownloaderConfig:(SDWebImageDownloaderConfig *)defaultDownloaderConfig { + if (defaultDownloaderConfig) { + _defaultDownloaderConfig = defaultDownloaderConfig; + } +} + +- (instancetype)init { + self = [super init]; + if (self) { + _shouldDecompressImages = YES; + _maxConcurrentDownloads = 3; + _downloadTimeout = 15.0; + _executionOrder = SDWebImageDownloaderFIFOExecutionOrder; + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + SDWebImageDownloaderConfig *config = [[[self class] allocWithZone:zone] init]; + config.shouldDecompressImages = self.shouldDecompressImages; + config.maxConcurrentDownloads = self.maxConcurrentDownloads; + config.downloadTimeout = self.downloadTimeout; + config.sessionConfiguration = [self.sessionConfiguration copyWithZone:zone]; + config.operationClass = self.operationClass; + config.executionOrder = self.executionOrder; + config.urlCredential = [self.urlCredential copyWithZone:zone]; + config.username = [self.username copyWithZone:zone]; + config.password = [self.password copyWithZone:zone]; + + return config; +} + + +@end diff --git a/SDWebImage/SDWebImageDownloaderOperation.h b/SDWebImage/SDWebImageDownloaderOperation.h index 782fe6ae..d43988f4 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.h +++ b/SDWebImage/SDWebImageDownloaderOperation.h @@ -21,7 +21,7 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification Describes a downloader operation. If one wants to use a custom downloader op, it needs to inherit from `NSOperation` and conform to this protocol For the description about these methods, see `SDWebImageDownloaderOperation` */ -@protocol SDWebImageDownloaderOperationInterface +@protocol SDWebImageDownloaderOperation - (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request inSession:(nullable NSURLSession *)session @@ -46,7 +46,7 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification @end -@interface SDWebImageDownloaderOperation : NSOperation +@interface SDWebImageDownloaderOperation : NSOperation /** * The request used by the operation's task. diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index dfff3559..6febe2d7 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -28,7 +28,7 @@ /** * A class that fits the NSOperation+SDWebImageDownloaderOperationInterface requirement so we can test */ -@interface CustomDownloaderOperation : NSOperation +@interface CustomDownloaderOperation : NSOperation @property (nonatomic, assign) BOOL shouldDecompressImages; @property (nonatomic, strong, nullable) NSURLCredential *credential; @@ -103,26 +103,26 @@ } - (void)test05ThatSetAndGetMaxConcurrentDownloadsWorks { - NSInteger initialValue = [SDWebImageDownloader sharedDownloader].maxConcurrentDownloads; + NSInteger initialValue = SDWebImageDownloader.sharedDownloader.config.maxConcurrentDownloads; - [[SDWebImageDownloader sharedDownloader] setMaxConcurrentDownloads:3]; - expect([SDWebImageDownloader sharedDownloader].maxConcurrentDownloads).to.equal(3); + SDWebImageDownloader.sharedDownloader.config.maxConcurrentDownloads = 3; + expect(SDWebImageDownloader.sharedDownloader.config.maxConcurrentDownloads).to.equal(3); - [[SDWebImageDownloader sharedDownloader] setMaxConcurrentDownloads:initialValue]; + SDWebImageDownloader.sharedDownloader.config.maxConcurrentDownloads = initialValue; } - (void)test06ThatUsingACustomDownloaderOperationWorks { // we try to set a usual NSOperation as operation class. Should not work - [[SDWebImageDownloader sharedDownloader] setOperationClass:[NSOperation class]]; - expect([SDWebImageDownloader sharedDownloader].operationClass).to.equal([SDWebImageDownloaderOperation class]); + SDWebImageDownloader.sharedDownloader.config.operationClass = [NSOperation class]; + expect(SDWebImageDownloader.sharedDownloader.config.operationClass).to.equal([SDWebImageDownloaderOperation class]); // setting an NSOperation subclass that conforms to SDWebImageDownloaderOperationInterface - should work - [[SDWebImageDownloader sharedDownloader] setOperationClass:[CustomDownloaderOperation class]]; - expect([SDWebImageDownloader sharedDownloader].operationClass).to.equal([CustomDownloaderOperation class]); + SDWebImageDownloader.sharedDownloader.config.operationClass = [CustomDownloaderOperation class]; + expect(SDWebImageDownloader.sharedDownloader.config.operationClass).to.equal([CustomDownloaderOperation class]); // back to the original value - [[SDWebImageDownloader sharedDownloader] setOperationClass:nil]; - expect([SDWebImageDownloader sharedDownloader].operationClass).to.equal([SDWebImageDownloaderOperation class]); + SDWebImageDownloader.sharedDownloader.config.operationClass = nil; + expect(SDWebImageDownloader.sharedDownloader.config.operationClass).to.equal([SDWebImageDownloaderOperation class]); } - (void)test07ThatAddProgressCallbackCompletedBlockWithNilURLCallsTheCompletionBlockWithNils { @@ -139,8 +139,8 @@ - (void)test08ThatAHTTPAuthDownloadWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"HTTP Auth download"]; - [SDWebImageDownloader sharedDownloader].username = @"httpwatch"; - [SDWebImageDownloader sharedDownloader].password = @"httpwatch01"; + SDWebImageDownloader.sharedDownloader.config.username = @"httpwatch"; + SDWebImageDownloader.sharedDownloader.config.password = @"httpwatch01"; NSURL *imageURL = [NSURL URLWithString:@"http://www.httpwatch.com/httpgallery/authentication/authenticatedimage/default.aspx?0.35786508303135633"]; [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { if (image && data && !error && finished) { @@ -150,8 +150,8 @@ } }]; [self waitForExpectationsWithCommonTimeout]; - [SDWebImageDownloader sharedDownloader].username = nil; - [SDWebImageDownloader sharedDownloader].password = nil; + SDWebImageDownloader.sharedDownloader.config.username = nil; + SDWebImageDownloader.sharedDownloader.config.password = nil; } - (void)test09ThatProgressiveJPEGWorks { diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index 0e1acf88..c6c4fb3b 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -27,6 +27,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import +#import #import #import #import From 47aa73a43658f61211a5ee9ae3b64448b2ec9784 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 31 Mar 2018 15:02:10 +0800 Subject: [PATCH 087/361] Update the downloader token's property to match the comments --- SDWebImage/SDWebImageDownloader.h | 12 ++++---- SDWebImage/SDWebImageDownloader.m | 37 ++++++++++++++++--------- SDWebImage/SDWebImageDownloaderConfig.h | 29 ++++++++++++------- SDWebImage/SDWebImageDownloaderConfig.m | 2 +- 4 files changed, 50 insertions(+), 30 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 3690986d..f2c87b12 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -92,14 +92,14 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB @interface SDWebImageDownloadToken : NSObject /** - The download's URL. This should be readonly and you should not modify + Cancel the current download. */ -@property (nonatomic, strong, nullable) NSURL *url; +- (void)cancel; + /** - The cancel token taken from `addHandlersForProgress:completed`. This should be readonly and you should not modify - @note use `-[SDWebImageDownloadToken cancel]` to cancel the token + The download's URL. */ -@property (nonatomic, strong, nullable) id downloadOperationCancelToken; +@property (nonatomic, strong, nullable, readonly) NSURL *url; @end @@ -139,7 +139,7 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB @property (nonatomic, assign, readonly) NSUInteger currentDownloadCount; /** - * Returns the global shared downloader instance. Which use the `SDWebImageDownloaderConfig.defaultDownloaderConfiguration` config. + * Returns the global shared downloader instance. Which use the `SDWebImageDownloaderConfig.defaultDownloaderConfig` config. */ @property (nonatomic, class, readonly, nonnull) SDWebImageDownloader *sharedDownloader; diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 050f60b0..946d63f5 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -15,20 +15,10 @@ @interface SDWebImageDownloadToken () +@property (nonatomic, strong, nullable, readwrite) NSURL *url; +@property (nonatomic, strong, nullable, readwrite) id downloadOperationCancelToken; @property (nonatomic, weak, nullable) NSOperation *downloadOperation; - -@end - -@implementation SDWebImageDownloadToken - -- (void)cancel { - if (self.downloadOperation) { - SDWebImageDownloadToken *cancelToken = self.downloadOperationCancelToken; - if (cancelToken) { - [self.downloadOperation cancel:cancelToken]; - } - } -} +@property (nonatomic, weak, nullable) SDWebImageDownloader *downloader; @end @@ -284,6 +274,7 @@ token.downloadOperation = operation; token.url = url; token.downloadOperationCancelToken = downloadOperationCancelToken; + token.downloader = self; return token; } @@ -398,3 +389,23 @@ didReceiveResponse:(NSURLResponse *)response } @end + +@implementation SDWebImageDownloadToken + +- (void)cancel { + @synchronized (self) { + if (!self.downloadOperationCancelToken) { + return; + } + if (self.downloader) { + // Downloader is alive, cancel token + [self.downloader cancel:self]; + } else { + // Downloader is dealloced, only cancel download operation + [self.downloadOperation cancel:self.downloadOperationCancelToken]; + } + self.downloadOperationCancelToken = nil; + } +} + +@end diff --git a/SDWebImage/SDWebImageDownloaderConfig.h b/SDWebImage/SDWebImageDownloaderConfig.h index 1b3b52e8..70f3dc54 100644 --- a/SDWebImage/SDWebImageDownloaderConfig.h +++ b/SDWebImage/SDWebImageDownloaderConfig.h @@ -24,7 +24,8 @@ typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { @interface SDWebImageDownloaderConfig : NSObject /** - Gets/Sets the default downloader config. + Gets/Sets the default downloader config used for shared instance or initialization when it does not provide any downloader config. Such as `SDWebImageDownloader.sharedDownloader`. + @note You should not pass nil to this value. */ @property (nonatomic, class, nonnull) SDWebImageDownloaderConfig *defaultDownloaderConfig; @@ -35,46 +36,54 @@ typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { @property (nonatomic, assign) BOOL shouldDecompressImages; /** - * The maximum number of concurrent downloads + * The maximum number of concurrent downloads. + * Defaults to 6. */ @property (nonatomic, assign) NSInteger maxConcurrentDownloads; /** - * The timeout value (in seconds) for the download operation. Default: 15.0. + * The timeout value (in seconds) for the download operation. + * Defaults to 15.0. */ @property (nonatomic, assign) NSTimeInterval downloadTimeout; /** - * The custom session configuration in use by NSURLSession. + * The custom session configuration in use by NSURLSession. If you don't provide one, we will use `defaultSessionConfiguration` instead. + * Defatuls to nil. + * @note The `timeoutIntervalForRequest` will be override by `downloadTimeout` config. */ -@property (nonatomic, strong, nonnull) NSURLSessionConfiguration *sessionConfiguration; +@property (nonatomic, strong, nullable) NSURLSessionConfiguration *sessionConfiguration; /** * Gets/Sets a subclass of `SDWebImageDownloaderOperation` as the default * `NSOperation` to be used each time SDWebImage constructs a request * operation to download an image. - * + * Defaults to nil. * @note Passing `NSOperation` to set as default. Passing `nil` will revert to `SDWebImageDownloaderOperation`. */ @property (nonatomic, assign, nullable) Class operationClass; /** - * Changes download operations execution order. Default value is `SDWebImageDownloaderFIFOExecutionOrder`. + * Changes download operations execution order. + * Defaults to `SDWebImageDownloaderFIFOExecutionOrder`. */ @property (nonatomic, assign) SDWebImageDownloaderExecutionOrder executionOrder; /** - * Set the default URL credential to be set for request operations. + * Set the default URL credential to be set for request operations. + * Defaults to nil. */ @property (nonatomic, strong, nullable) NSURLCredential *urlCredential; /** - * Set username + * Set username using for HTTP Basic authentication. + * Defaults to nil. */ @property (nonatomic, copy, nullable) NSString *username; /** - * Set password + * Set password using for HTTP Basic authentication. + * Defautls to nil. */ @property (nonatomic, copy, nullable) NSString *password; diff --git a/SDWebImage/SDWebImageDownloaderConfig.m b/SDWebImage/SDWebImageDownloaderConfig.m index 2783af14..1a9f0f88 100644 --- a/SDWebImage/SDWebImageDownloaderConfig.m +++ b/SDWebImage/SDWebImageDownloaderConfig.m @@ -29,7 +29,7 @@ static SDWebImageDownloaderConfig * _defaultDownloaderConfig; self = [super init]; if (self) { _shouldDecompressImages = YES; - _maxConcurrentDownloads = 3; + _maxConcurrentDownloads = 6; _downloadTimeout = 15.0; _executionOrder = SDWebImageDownloaderFIFOExecutionOrder; } From 6e402ce41c9d069bace8b2634821df7a92005dc6 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 31 Mar 2018 15:51:46 +0800 Subject: [PATCH 088/361] Add KVO for maxConcurrentDownloads to allow dynamic change --- SDWebImage/SDWebImageDownloader.h | 3 +- SDWebImage/SDWebImageDownloader.m | 47 +++++++++++++++++-------- SDWebImage/SDWebImageDownloaderConfig.h | 4 +-- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index f2c87b12..b5ff037b 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -110,7 +110,8 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB @interface SDWebImageDownloader : NSObject /** - Downloader Config object - storing all kind of settings + * Downloader Config object - storing all kind of settings. + * Most config properties support dynamic changes during download, except something like `sessionConfiguration`, see `SDWebImageDownloaderConfig` for more detail. */ @property (nonatomic, copy, readonly, nonnull) SDWebImageDownloaderConfig *config; diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 946d63f5..8b0269a1 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -10,6 +10,8 @@ #import "SDWebImageDownloaderConfig.h" #import "SDWebImageDownloaderOperation.h" +static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; + #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); #define UNLOCK(lock) dispatch_semaphore_signal(lock); @@ -82,8 +84,9 @@ config = SDWebImageDownloaderConfig.defaultDownloaderConfig; } _config = [config copy]; + [_config addObserver:self forKeyPath:NSStringFromSelector(@selector(maxConcurrentDownloads)) options:0 context:SDWebImageDownloaderContext]; _downloadQueue = [NSOperationQueue new]; - _downloadQueue.maxConcurrentOperationCount = 6; + _downloadQueue.maxConcurrentOperationCount = _config.maxConcurrentDownloads; _downloadQueue.name = @"com.hackemist.SDWebImageDownloader"; _URLOperations = [NSMutableDictionary new]; #ifdef SD_WEBP @@ -97,7 +100,6 @@ if (!sessionConfiguration) { sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; } - sessionConfiguration.timeoutIntervalForRequest = _config.downloadTimeout; /** * Create the session for this task * We send nil as delegate queue so that the session creates a serial operation queue for performing all delegate @@ -110,6 +112,14 @@ return self; } +- (void)dealloc { + [self.session invalidateAndCancel]; + self.session = nil; + + [self.downloadQueue cancelAllOperations]; + [self.config removeObserver:self forKeyPath:NSStringFromSelector(@selector(maxConcurrentDownloads)) context:SDWebImageDownloaderContext]; +} + - (void)invalidateSessionAndCancel:(BOOL)cancelPendingOperations { if (self == [SDWebImageDownloader sharedDownloader]) { return; @@ -121,17 +131,6 @@ } } -- (void)dealloc { - [self.session invalidateAndCancel]; - self.session = nil; - - [self.downloadQueue cancelAllOperations]; -} - -- (NSURLSessionConfiguration *)sessionConfiguration { - return self.session.configuration; -} - - (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field { LOCK(self.headersLock); if (value) { @@ -279,6 +278,12 @@ return token; } +- (void)cancelAllDownloads { + [self.downloadQueue cancelAllOperations]; +} + +#pragma mark - Properties + - (BOOL)isSuspended { return self.downloadQueue.isSuspended; } @@ -291,8 +296,20 @@ return self.downloadQueue.operationCount; } -- (void)cancelAllDownloads { - [self.downloadQueue cancelAllOperations]; +- (NSURLSessionConfiguration *)sessionConfiguration { + return self.session.configuration; +} + +#pragma mark - KVO + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if (context == SDWebImageDownloaderContext) { + if ([keyPath isEqualToString:NSStringFromSelector(@selector(maxConcurrentDownloads))]) { + self.downloadQueue.maxConcurrentOperationCount = self.config.maxConcurrentDownloads; + } + } else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; + } } #pragma mark Helper methods diff --git a/SDWebImage/SDWebImageDownloaderConfig.h b/SDWebImage/SDWebImageDownloaderConfig.h index 70f3dc54..c4e3792c 100644 --- a/SDWebImage/SDWebImageDownloaderConfig.h +++ b/SDWebImage/SDWebImageDownloaderConfig.h @@ -42,7 +42,7 @@ typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { @property (nonatomic, assign) NSInteger maxConcurrentDownloads; /** - * The timeout value (in seconds) for the download operation. + * The timeout value (in seconds) for each download operation. * Defaults to 15.0. */ @property (nonatomic, assign) NSTimeInterval downloadTimeout; @@ -50,7 +50,7 @@ typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { /** * The custom session configuration in use by NSURLSession. If you don't provide one, we will use `defaultSessionConfiguration` instead. * Defatuls to nil. - * @note The `timeoutIntervalForRequest` will be override by `downloadTimeout` config. + * @note This property does not support dynamic changes, means it's immutable after the downloader instance initialized. */ @property (nonatomic, strong, nullable) NSURLSessionConfiguration *sessionConfiguration; From be36009d1002bfc641272394ae1cc7e5da7ec54f Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 31 Mar 2018 18:29:55 +0800 Subject: [PATCH 089/361] Update the test for custom download operation class. --- Tests/Tests/SDWebImageDownloaderTests.m | 32 ++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index 6febe2d7..cfc3c635 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -16,6 +16,10 @@ /** * Category for SDWebImageDownloader so we can access the operationClass */ +@interface SDWebImageDownloadToken () +@property (nonatomic, weak, nullable) NSOperation *downloadOperation; +@end + @interface SDWebImageDownloader () @property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue; @@ -26,7 +30,7 @@ @end /** - * A class that fits the NSOperation+SDWebImageDownloaderOperationInterface requirement so we can test + * A class that fits the NSOperation+SDWebImageDownloaderOperation requirement so we can test */ @interface CustomDownloaderOperation : NSOperation @@ -112,17 +116,29 @@ } - (void)test06ThatUsingACustomDownloaderOperationWorks { + SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] initWithConfig:nil]; + NSURL *imageURL1 = [NSURL URLWithString:kTestJpegURL]; + NSURL *imageURL2 = [NSURL URLWithString:kTestPNGURL]; + NSURL *imageURL3 = [NSURL URLWithString:kTestGIFURL]; // we try to set a usual NSOperation as operation class. Should not work - SDWebImageDownloader.sharedDownloader.config.operationClass = [NSOperation class]; - expect(SDWebImageDownloader.sharedDownloader.config.operationClass).to.equal([SDWebImageDownloaderOperation class]); + downloader.config.operationClass = [NSOperation class]; + SDWebImageDownloadToken *token = [downloader downloadImageWithURL:imageURL1 options:0 progress:nil completed:nil]; + NSOperation *operation = token.downloadOperation; + expect([operation class]).to.equal([SDWebImageDownloaderOperation class]); - // setting an NSOperation subclass that conforms to SDWebImageDownloaderOperationInterface - should work - SDWebImageDownloader.sharedDownloader.config.operationClass = [CustomDownloaderOperation class]; - expect(SDWebImageDownloader.sharedDownloader.config.operationClass).to.equal([CustomDownloaderOperation class]); + // setting an NSOperation subclass that conforms to SDWebImageDownloaderOperation - should work + downloader.config.operationClass = [CustomDownloaderOperation class]; + token = [downloader downloadImageWithURL:imageURL2 options:0 progress:nil completed:nil]; + operation = token.downloadOperation; + expect([operation class]).to.equal([CustomDownloaderOperation class]); // back to the original value - SDWebImageDownloader.sharedDownloader.config.operationClass = nil; - expect(SDWebImageDownloader.sharedDownloader.config.operationClass).to.equal([SDWebImageDownloaderOperation class]); + downloader.config.operationClass = nil; + token = [downloader downloadImageWithURL:imageURL3 options:0 progress:nil completed:nil]; + operation = token.downloadOperation; + expect([operation class]).to.equal([SDWebImageDownloaderOperation class]); + + [downloader invalidateSessionAndCancel:YES]; } - (void)test07ThatAddProgressCallbackCompletedBlockWithNilURLCallsTheCompletionBlockWithNils { From 321101fa60f4da37ccb4609bb03620282af05610 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 5 Apr 2018 01:35:59 +0800 Subject: [PATCH 090/361] Use NS_EXTENSIBLE_STRING_ENUM instead of NS_STRING_ENUM --- SDWebImage/SDWebImageDefine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index bfeafaae..2f2f6a8c 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -9,7 +9,7 @@ #import "SDWebImageCompat.h" typedef void(^SDWebImageNoParamsBlock)(void); -typedef NSString * SDWebImageContextOption NS_STRING_ENUM; +typedef NSString * SDWebImageContextOption NS_EXTENSIBLE_STRING_ENUM; typedef NSDictionary SDWebImageContext; typedef NSMutableDictionary SDWebImageMutableContext; From 793b7e33a8c1758d34ddd599ef60eb2ca80219e7 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 5 Apr 2018 02:26:38 +0800 Subject: [PATCH 091/361] Update the custom downloader operation to fix test --- .../project.pbxproj | 8 +++ Tests/Tests/SDWebImageDownloaderTests.m | 41 +----------- Tests/Tests/SDWebImageTestDownloadOperation.h | 23 +++++++ Tests/Tests/SDWebImageTestDownloadOperation.m | 66 +++++++++++++++++++ 4 files changed, 100 insertions(+), 38 deletions(-) create mode 100644 Tests/Tests/SDWebImageTestDownloadOperation.h create mode 100644 Tests/Tests/SDWebImageTestDownloadOperation.m diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 4209b95d..940677b8 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -12,6 +12,8 @@ 2D7AF0601F329763000083C2 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; }; 321259EC1F39E3240096FE0E /* TestImageStatic.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259EB1F39E3240096FE0E /* TestImageStatic.webp */; }; 321259EE1F39E4110096FE0E /* TestImageAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */; }; + 3226ECBB20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */; }; + 3226ECBC20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */; }; 3254C32020641077008D1022 /* SDWebImageTransformerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */; }; 3254C32120641077008D1022 /* SDWebImageTransformerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */; }; 3264FF2F205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */; }; @@ -63,6 +65,8 @@ 2D7AF05F1F329763000083C2 /* SDTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDTestCase.m; sourceTree = ""; }; 321259EB1F39E3240096FE0E /* TestImageStatic.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageStatic.webp; sourceTree = ""; }; 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageAnimated.webp; sourceTree = ""; }; + 3226ECB920754F7700FAFACF /* SDWebImageTestDownloadOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestDownloadOperation.h; sourceTree = ""; }; + 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestDownloadOperation.m; sourceTree = ""; }; 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransformerTests.m; sourceTree = ""; }; 3264FF2D205D42CB00F6BD48 /* SDWebImageTestTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestTransformer.h; sourceTree = ""; }; 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestTransformer.m; sourceTree = ""; }; @@ -206,6 +210,8 @@ 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */, 2D7AF05E1F329763000083C2 /* SDTestCase.h */, 2D7AF05F1F329763000083C2 /* SDTestCase.m */, + 3226ECB920754F7700FAFACF /* SDWebImageTestDownloadOperation.h */, + 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */, 32E6F0301F3A1B4700A945E6 /* SDWebImageTestDecoder.h */, 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */, 3264FF2D205D42CB00F6BD48 /* SDWebImageTestTransformer.h */, @@ -469,6 +475,7 @@ 32B99EA9203B34B60017FD66 /* SDWebImageDecoderTests.m in Sources */, 3264FF30205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */, 32B99E9B203B2EDD0017FD66 /* SDTestCase.m in Sources */, + 3226ECBC20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -477,6 +484,7 @@ buildActionMask = 2147483647; files = ( 32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */, + 3226ECBB20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */, 3254C32020641077008D1022 /* SDWebImageTransformerTests.m in Sources */, 32A571562037DB2D002EDAAE /* SDAnimatedImageTest.m in Sources */, 1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */, diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index cfc3c635..b3839e2e 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -11,6 +11,7 @@ #import #import #import +#import "SDWebImageTestDownloadOperation.h" #import "SDWebImageTestDecoder.h" /** @@ -29,42 +30,6 @@ createCallback:(SDWebImageDownloaderOperation *(^)(void))createCallback; @end -/** - * A class that fits the NSOperation+SDWebImageDownloaderOperation requirement so we can test - */ -@interface CustomDownloaderOperation : NSOperation - -@property (nonatomic, assign) BOOL shouldDecompressImages; -@property (nonatomic, strong, nullable) NSURLCredential *credential; - -@end - -@implementation CustomDownloaderOperation - -- (instancetype)initWithRequest:(NSURLRequest *)request inSession:(NSURLSession *)session options:(SDWebImageDownloaderOptions)options { - return [self initWithRequest:request inSession:session options:options context:nil]; -} - -- (instancetype)initWithRequest:(NSURLRequest *)request inSession:(NSURLSession *)session options:(SDWebImageDownloaderOptions)options context:(SDWebImageContext *)context { - self = [super init]; - if (self) { - - } - return self; -} - -- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock { - return nil; -} - -- (BOOL)cancel:(id)token { - return YES; -} - -@end - - @interface SDWebImageDownloaderTests : SDTestCase @@ -127,10 +92,10 @@ expect([operation class]).to.equal([SDWebImageDownloaderOperation class]); // setting an NSOperation subclass that conforms to SDWebImageDownloaderOperation - should work - downloader.config.operationClass = [CustomDownloaderOperation class]; + downloader.config.operationClass = [SDWebImageTestDownloadOperation class]; token = [downloader downloadImageWithURL:imageURL2 options:0 progress:nil completed:nil]; operation = token.downloadOperation; - expect([operation class]).to.equal([CustomDownloaderOperation class]); + expect([operation class]).to.equal([SDWebImageTestDownloadOperation class]); // back to the original value downloader.config.operationClass = nil; diff --git a/Tests/Tests/SDWebImageTestDownloadOperation.h b/Tests/Tests/SDWebImageTestDownloadOperation.h new file mode 100644 index 00000000..90fcc55b --- /dev/null +++ b/Tests/Tests/SDWebImageTestDownloadOperation.h @@ -0,0 +1,23 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Matt Galloway + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import + +/** + * A class that fits the NSOperation+SDWebImageDownloaderOperation requirement so we can test + */ +@interface SDWebImageTestDownloadOperation : NSOperation + +@property (nonatomic, assign) BOOL shouldDecompressImages; +@property (nonatomic, strong, nullable) NSURLCredential *credential; +@property (nonatomic, strong, nullable) NSURLRequest *request; +@property (nonatomic, strong, nullable) NSURLResponse *response; + +@end diff --git a/Tests/Tests/SDWebImageTestDownloadOperation.m b/Tests/Tests/SDWebImageTestDownloadOperation.m new file mode 100644 index 00000000..cec3f399 --- /dev/null +++ b/Tests/Tests/SDWebImageTestDownloadOperation.m @@ -0,0 +1,66 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Matt Galloway + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageTestDownloadOperation.h" + +@implementation SDWebImageTestDownloadOperation + +@synthesize executing = _executing; +@synthesize finished = _finished; + +- (void)start { + self.finished = NO; + self.executing = YES; + // Do nothing but keep running +} + +- (void)cancel { + if (self.isFinished) return; + [super cancel]; +} + +- (BOOL)isConcurrent { + return YES; +} + +- (void)setFinished:(BOOL)finished { + [self willChangeValueForKey:@"isFinished"]; + _finished = finished; + [self didChangeValueForKey:@"isFinished"]; +} + +- (void)setExecuting:(BOOL)executing { + [self willChangeValueForKey:@"isExecuting"]; + _executing = executing; + [self didChangeValueForKey:@"isExecuting"]; +} + +- (instancetype)initWithRequest:(NSURLRequest *)request inSession:(NSURLSession *)session options:(SDWebImageDownloaderOptions)options { + return [self initWithRequest:request inSession:session options:options context:nil]; +} + +- (instancetype)initWithRequest:(NSURLRequest *)request inSession:(NSURLSession *)session options:(SDWebImageDownloaderOptions)options context:(SDWebImageContext *)context { + self = [super init]; + if (self) { + self.request = request; + } + return self; +} + +- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock { + return NSStringFromClass([self class]); +} + +- (BOOL)cancel:(id)token { + [self cancel]; + return YES; +} + +@end From 73c811dc23973e4ee2a69a13c5e016eaff3cc46f Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 5 Apr 2018 07:26:50 +0800 Subject: [PATCH 092/361] Fix all code tied with SDWebImageDownloaderOperation class but not protocol, which previously relay on NSURLSession but it should not to be --- SDWebImage/SDWebImageDownloader.m | 42 ++++++++++--------- SDWebImage/SDWebImageDownloaderOperation.h | 23 ++++++---- Tests/Tests/SDWebImageTestDownloadOperation.m | 15 +++++++ 3 files changed, 53 insertions(+), 27 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 8b0269a1..1ccb2969 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -21,6 +21,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; @property (nonatomic, strong, nullable, readwrite) id downloadOperationCancelToken; @property (nonatomic, weak, nullable) NSOperation *downloadOperation; @property (nonatomic, weak, nullable) SDWebImageDownloader *downloader; +@property (nonatomic, assign, getter=isCancelled) BOOL cancelled; @end @@ -29,7 +30,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; @property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue; @property (weak, nonatomic, nullable) NSOperation *lastAddedOperation; -@property (strong, nonatomic, nonnull) NSMutableDictionary *URLOperations; +@property (strong, nonatomic, nonnull) NSMutableDictionary *> *URLOperations; @property (strong, nonatomic, nullable) SDHTTPHeadersMutableDictionary *HTTPHeaders; @property (strong, nonatomic, nonnull) dispatch_semaphore_t operationsLock; // a lock to keep the access to `URLOperations` thread-safe @property (strong, nonatomic, nonnull) dispatch_semaphore_t headersLock; // a lock to keep the access to `HTTPHeaders` thread-safe @@ -166,7 +167,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock { __weak SDWebImageDownloader *wself = self; - return [self addProgressCallback:progressBlock completedBlock:completedBlock forURL:url createCallback:^SDWebImageDownloaderOperation *{ + return [self addProgressCallback:progressBlock completedBlock:completedBlock forURL:url createCallback:^NSOperation *{ __strong __typeof (wself) sself = wself; NSTimeInterval timeoutInterval = sself.config.downloadTimeout; if (timeoutInterval == 0.0) { @@ -193,7 +194,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; } else { operationClass = [SDWebImageDownloaderOperation class]; } - SDWebImageDownloaderOperation *operation = [[operationClass alloc] initWithRequest:request inSession:sself.session options:options context:context]; + NSOperation *operation = [[operationClass alloc] initWithRequest:request inSession:sself.session options:options context:context]; operation.shouldDecompressImages = sself.config.shouldDecompressImages; if (sself.config.urlCredential) { @@ -224,7 +225,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; return; } LOCK(self.operationsLock); - SDWebImageDownloaderOperation *operation = [self.URLOperations objectForKey:url]; + NSOperation *operation = [self.URLOperations objectForKey:url]; if (operation) { BOOL canceled = [operation cancel:token.downloadOperationCancelToken]; if (canceled) { @@ -237,7 +238,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; - (nullable SDWebImageDownloadToken *)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock forURL:(nullable NSURL *)url - createCallback:(SDWebImageDownloaderOperation *(^)(void))createCallback { + createCallback:(NSOperation *(^)(void))createCallback { // The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data. if (url == nil) { if (completedBlock != nil) { @@ -247,7 +248,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; } LOCK(self.operationsLock); - SDWebImageDownloaderOperation *operation = [self.URLOperations objectForKey:url]; + NSOperation *operation = [self.URLOperations objectForKey:url]; if (!operation) { operation = createCallback(); __weak typeof(self) wself = self; @@ -314,12 +315,14 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; #pragma mark Helper methods -- (SDWebImageDownloaderOperation *)operationWithTask:(NSURLSessionTask *)task { - SDWebImageDownloaderOperation *returnOperation = nil; - for (SDWebImageDownloaderOperation *operation in self.downloadQueue.operations) { - if (operation.dataTask.taskIdentifier == task.taskIdentifier) { - returnOperation = operation; - break; +- (NSOperation *)operationWithTask:(NSURLSessionTask *)task { + NSOperation *returnOperation = nil; + for (NSOperation *operation in self.downloadQueue.operations) { + if ([operation respondsToSelector:@selector(dataTask)]) { + if (operation.dataTask.taskIdentifier == task.taskIdentifier) { + returnOperation = operation; + break; + } } } return returnOperation; @@ -333,7 +336,7 @@ didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { // Identify the operation that runs this task and pass it the delegate method - SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask]; + NSOperation *dataOperation = [self operationWithTask:dataTask]; if ([dataOperation respondsToSelector:@selector(URLSession:dataTask:didReceiveResponse:completionHandler:)]) { [dataOperation URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler]; } else { @@ -346,7 +349,7 @@ didReceiveResponse:(NSURLResponse *)response - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { // Identify the operation that runs this task and pass it the delegate method - SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask]; + NSOperation *dataOperation = [self operationWithTask:dataTask]; if ([dataOperation respondsToSelector:@selector(URLSession:dataTask:didReceiveData:)]) { [dataOperation URLSession:session dataTask:dataTask didReceiveData:data]; } @@ -358,7 +361,7 @@ didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler { // Identify the operation that runs this task and pass it the delegate method - SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask]; + NSOperation *dataOperation = [self operationWithTask:dataTask]; if ([dataOperation respondsToSelector:@selector(URLSession:dataTask:willCacheResponse:completionHandler:)]) { [dataOperation URLSession:session dataTask:dataTask willCacheResponse:proposedResponse completionHandler:completionHandler]; } else { @@ -373,7 +376,7 @@ didReceiveResponse:(NSURLResponse *)response - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { // Identify the operation that runs this task and pass it the delegate method - SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:task]; + NSOperation *dataOperation = [self operationWithTask:task]; if ([dataOperation respondsToSelector:@selector(URLSession:task:didCompleteWithError:)]) { [dataOperation URLSession:session task:task didCompleteWithError:error]; } @@ -382,7 +385,7 @@ didReceiveResponse:(NSURLResponse *)response - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler { // Identify the operation that runs this task and pass it the delegate method - SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:task]; + NSOperation *dataOperation = [self operationWithTask:task]; if ([dataOperation respondsToSelector:@selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)]) { [dataOperation URLSession:session task:task willPerformHTTPRedirection:response newRequest:request completionHandler:completionHandler]; } else { @@ -395,7 +398,7 @@ didReceiveResponse:(NSURLResponse *)response - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { // Identify the operation that runs this task and pass it the delegate method - SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:task]; + NSOperation *dataOperation = [self operationWithTask:task]; if ([dataOperation respondsToSelector:@selector(URLSession:task:didReceiveChallenge:completionHandler:)]) { [dataOperation URLSession:session task:task didReceiveChallenge:challenge completionHandler:completionHandler]; } else { @@ -411,9 +414,10 @@ didReceiveResponse:(NSURLResponse *)response - (void)cancel { @synchronized (self) { - if (!self.downloadOperationCancelToken) { + if (self.isCancelled) { return; } + self.cancelled = YES; if (self.downloader) { // Downloader is alive, cancel token [self.downloader cancel:self]; diff --git a/SDWebImage/SDWebImageDownloaderOperation.h b/SDWebImage/SDWebImageDownloaderOperation.h index d43988f4..7c42a34f 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.h +++ b/SDWebImage/SDWebImageDownloaderOperation.h @@ -20,9 +20,10 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification /** Describes a downloader operation. If one wants to use a custom downloader op, it needs to inherit from `NSOperation` and conform to this protocol For the description about these methods, see `SDWebImageDownloaderOperation` + @note If your custom operation class does not use `NSURLSession` at all, do not implement the optional methods and session delegate methods. */ -@protocol SDWebImageDownloaderOperation - +@protocol SDWebImageDownloaderOperation +@required - (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request inSession:(nullable NSURLSession *)session options:(SDWebImageDownloaderOptions)options; @@ -43,16 +44,27 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification - (BOOL)cancel:(nullable id)token; +- (nullable NSURLRequest *)request; +- (nullable NSURLResponse *)response; + +@optional +- (nullable NSURLSessionTask *)dataTask; + @end -@interface SDWebImageDownloaderOperation : NSOperation +@interface SDWebImageDownloaderOperation : NSOperation /** * The request used by the operation's task. */ @property (strong, nonatomic, readonly, nullable) NSURLRequest *request; +/** + * The response returned by the operation's task. + */ +@property (strong, nonatomic, nullable, readonly) NSURLResponse *response; + /** * The operation's task */ @@ -86,11 +98,6 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification */ @property (assign, nonatomic, readonly) NSInteger expectedSize; -/** - * The response returned by the operation's task. - */ -@property (strong, nonatomic, nullable, readonly) NSURLResponse *response; - /** * Initializes a `SDWebImageDownloaderOperation` object * diff --git a/Tests/Tests/SDWebImageTestDownloadOperation.m b/Tests/Tests/SDWebImageTestDownloadOperation.m index cec3f399..cb58a902 100644 --- a/Tests/Tests/SDWebImageTestDownloadOperation.m +++ b/Tests/Tests/SDWebImageTestDownloadOperation.m @@ -9,6 +9,12 @@ #import "SDWebImageTestDownloadOperation.h" +@interface SDWebImageTestDownloadOperation () + +@property (nonatomic, strong) NSMutableArray *completedBlocks; + +@end + @implementation SDWebImageTestDownloadOperation @synthesize executing = _executing; @@ -23,6 +29,11 @@ - (void)cancel { if (self.isFinished) return; [super cancel]; + + NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:nil]; + for (SDWebImageDownloaderCompletedBlock completedBlock in self.completedBlocks) { + completedBlock(nil, nil, error, YES); + } } - (BOOL)isConcurrent { @@ -49,12 +60,16 @@ self = [super init]; if (self) { self.request = request; + self.completedBlocks = [NSMutableArray array]; } return self; } - (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock { + if (completedBlock) { + [self.completedBlocks addObject:completedBlock]; + } return NSStringFromClass([self class]); } From 1d7dba33f589318c076458234d19abb82ab53a3b Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 5 Apr 2018 15:25:14 +0800 Subject: [PATCH 093/361] Update the test about download operation, which using protocol instead of class --- SDWebImage/SDWebImageOperation.h | 5 +++++ Tests/Tests/SDWebImageDownloaderTests.m | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/SDWebImage/SDWebImageOperation.h b/SDWebImage/SDWebImageOperation.h index 71094ee3..e92c13e0 100644 --- a/SDWebImage/SDWebImageOperation.h +++ b/SDWebImage/SDWebImageOperation.h @@ -13,3 +13,8 @@ - (void)cancel; @end + +// NSOperation conform to `SDWebImageOperation` +@interface NSOperation (SDWebImageOperation) + +@end diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index b3839e2e..d06d633d 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -27,7 +27,7 @@ - (nullable SDWebImageDownloadToken *)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock forURL:(nullable NSURL *)url - createCallback:(SDWebImageDownloaderOperation *(^)(void))createCallback; + createCallback:(NSOperation *(^)(void))createCallback; @end From 393085a9b0e92fa653bbedb59ff0d568e9db90cd Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 5 Apr 2018 18:44:38 +0800 Subject: [PATCH 094/361] Update the default downloader config to use the dispatch_once to avoid thread-safe issue --- SDWebImage/SDWebImageDownloaderConfig.h | 1 + SDWebImage/SDWebImageDownloaderConfig.m | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDWebImageDownloaderConfig.h b/SDWebImage/SDWebImageDownloaderConfig.h index c4e3792c..9f702bd6 100644 --- a/SDWebImage/SDWebImageDownloaderConfig.h +++ b/SDWebImage/SDWebImageDownloaderConfig.h @@ -25,6 +25,7 @@ typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { /** Gets/Sets the default downloader config used for shared instance or initialization when it does not provide any downloader config. Such as `SDWebImageDownloader.sharedDownloader`. + @note You can modify the property on default downloader config, which can be used for later created downloader instance. The already created downloader instance does not get affected. @note You should not pass nil to this value. */ @property (nonatomic, class, nonnull) SDWebImageDownloaderConfig *defaultDownloaderConfig; diff --git a/SDWebImage/SDWebImageDownloaderConfig.m b/SDWebImage/SDWebImageDownloaderConfig.m index 1a9f0f88..2d9d6136 100644 --- a/SDWebImage/SDWebImageDownloaderConfig.m +++ b/SDWebImage/SDWebImageDownloaderConfig.m @@ -13,9 +13,10 @@ static SDWebImageDownloaderConfig * _defaultDownloaderConfig; @implementation SDWebImageDownloaderConfig + (SDWebImageDownloaderConfig *)defaultDownloaderConfig { - if (!_defaultDownloaderConfig) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ _defaultDownloaderConfig = [SDWebImageDownloaderConfig new]; - } + }); return _defaultDownloaderConfig; } From 407b708b386df075ef2928fa7fbfb691f9de94d0 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 5 Apr 2018 22:09:05 +0800 Subject: [PATCH 095/361] Add shouldIncrementalLoad in SDAnimatedImageView to choose the animation behavior for progressive looading --- Examples/SDWebImage OSX Demo/ViewController.m | 2 +- SDWebImage/SDAnimatedImage.h | 2 +- SDWebImage/SDAnimatedImageRep.m | 3 +- SDWebImage/SDAnimatedImageView.h | 28 +++++---- SDWebImage/SDAnimatedImageView.m | 63 ++++++++++++------- 5 files changed, 59 insertions(+), 39 deletions(-) diff --git a/Examples/SDWebImage OSX Demo/ViewController.m b/Examples/SDWebImage OSX Demo/ViewController.m index eeda3c7a..cb7dbee8 100644 --- a/Examples/SDWebImage OSX Demo/ViewController.m +++ b/Examples/SDWebImage OSX Demo/ViewController.m @@ -28,7 +28,7 @@ [super viewDidLoad]; // For animated GIF rendering, set `animates` to YES or will only show the first frame - self.imageView2.animates = YES; // `SDAnimatedImageRep` be can used for built-in `NSImageView` to support better GIF & APNG rendering + self.imageView2.animates = YES; // `SDAnimatedImageRep` can be used for built-in `NSImageView` to support better GIF & APNG rendering as well. No need `SDAnimatedImageView` self.imageView3.animates = YES; self.imageView4.animates = YES; self.imageView1.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator; diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h index 968b47e9..00f2fb7f 100644 --- a/SDWebImage/SDAnimatedImage.h +++ b/SDWebImage/SDAnimatedImage.h @@ -18,7 +18,7 @@ @required /** 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. However, for progressive image decoding, we will use this instead. + @note Normally we use `initWithData:scale:` to create custom animated image class. However, for progressive image decoding, we will use this with animated coder which conforms to `SDWebImageProgressiveCoder` as well instead. @param animatedCoder An animated coder which conform `SDWebImageAnimatedCoder` protocol @param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property. diff --git a/SDWebImage/SDAnimatedImageRep.m b/SDWebImage/SDAnimatedImageRep.m index b922716a..e8b95cc9 100644 --- a/SDWebImage/SDAnimatedImageRep.m +++ b/SDWebImage/SDAnimatedImageRep.m @@ -87,10 +87,11 @@ } NSUInteger index = [value unsignedIntegerValue]; float frameDuration = 0; - // Through we currently process GIF only, in the 5.x we support APNG so we keep the extensibility if (CFStringCompare(type, kUTTypeGIF, 0) == kCFCompareEqualTo) { + // GIF frameDuration = [[SDWebImageGIFCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource]; } else if (CFStringCompare(type, kUTTypePNG, 0) == kCFCompareEqualTo) { + // APNG frameDuration = [[SDWebImageAPNGCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource]; } if (!frameDuration) { diff --git a/SDWebImage/SDAnimatedImageView.h b/SDWebImage/SDAnimatedImageView.h index fe824216..5038b1cb 100644 --- a/SDWebImage/SDAnimatedImageView.h +++ b/SDWebImage/SDAnimatedImageView.h @@ -15,25 +15,26 @@ /** A drop-in replacement for UIImageView/NSImageView, you can use this for animated image rendering. Call `setImage:` with `UIImage(NSImage)` which conform to `SDAnimatedImage` protocol will start animated image rendering. Call with normal UIImage(NSImage) will back to normal UIImageView(NSImageView) rendering - For UIKit: use `-startAnimating`, `-stopAnimating` to control animating - For AppKit: use `-setAnimates:` to control animating. This view is layer-backed. + For UIKit: use `-startAnimating`, `-stopAnimating` to control animating. `isAnimating` to check animation state. + For AppKit: use `-setAnimates:` to control animating, `animates` to check animation state. This view is layer-backed. */ @interface SDAnimatedImageView : UIImageView /** - Current display frame image + Current display frame image. */ @property (nonatomic, strong, readonly, nullable) UIImage *currentFrame; /** - Current frame index, zero based + Current frame index, zero based. This value is KVO Compliance. */ @property (nonatomic, assign, readonly) NSUInteger currentFrameIndex; /** - Current loop count since its latest animating + Current loop count since its latest animating. This value is KVO Compliance. */ @property (nonatomic, assign, readonly) NSUInteger currentLoopCount; /** - YES to choose `animationRepeatCount` property instead of image's loop count for animation loop count. Default is NO. + YES to choose `animationRepeatCount` property for animation loop count. No to use animated image's `animatedImageLoopCount` instead. + Default is NO. */ @property (nonatomic, assign) BOOL shouldCustomLoopCount; /** @@ -42,11 +43,6 @@ This class override UIImageView's `animationRepeatCount` property on iOS, use this property as well. */ @property (nonatomic, assign) NSInteger animationRepeatCount; -/** - Returns a Boolean value indicating whether the animation is running. - This class override UIImageView's `animating` property on iOS, use this property as well. - */ -@property (nonatomic, readonly, getter=isAnimating) BOOL animating; /** Provide a max buffer size by bytes. This is used to adjust frame buffer count and can be useful when the decoding cost is expensive (such as Animated WebP software decoding). Default is 0. `0` means automatically adjust by calculating current memory usage. @@ -54,12 +50,18 @@ `NSUIntegerMax` means cache all the buffer. (Lowest CPU and Highest Memory) */ @property (nonatomic, assign) NSUInteger maxBufferSize; +/** + Whehter or not to enable incremental image load for animated image. This is for the animated image which `sd_isIncremental` is YES (See `UIImage+WebCache.h`). If enable, animated image rendering will stop at the last frame available currently, and continue when another `setImage:` trigger, where the new animated image's `animatedImageData` should be updated from the previous one. If the `sd_isIncremental` is NO. The incremental image load stop. + @note If you are confused about this description, open Chrome browser to view some large GIF images with low network speed to see the animation behavior. + @note The best practice to use incremental load is using `initWithAnimatedCoder:scale` in `SDAnimatedImage` with animated coder which conform to `SDWebImageProgressiveCoder` as well. Then call incremental update and incremental decode method to produce the image. + Default is YES. Set to NO to only render the static poster for incremental animated image. + */ +@property (nonatomic, assign) BOOL shouldIncrementalLoad; /** You can specify a runloop mode to let it rendering. Default is NSRunLoopCommonModes on multi-core iOS device, NSDefaultRunLoopMode on single-core iOS device - This value has no use on macOS */ -@property (nonatomic, copy, nonnull) NSString *runLoopMode; +@property (nonatomic, copy, nonnull) NSRunLoopMode runLoopMode NS_AVAILABLE_IOS(3_1); @end diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index 6492e327..386efe88 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -210,6 +210,9 @@ dispatch_semaphore_signal(self->_lock); - (void)commonInit { + self.shouldCustomLoopCount = NO; + self.shouldIncrementalLoad = YES; + self.lock = dispatch_semaphore_create(1); #if SD_MAC self.wantsLayer = YES; // Default value from `NSImageView` @@ -217,14 +220,12 @@ dispatch_semaphore_signal(self->_lock); self.imageScaling = NSImageScaleProportionallyDown; self.imageAlignment = NSImageAlignCenter; #endif - self.runLoopMode = [[self class] defaultRunLoopMode]; - self.lock = dispatch_semaphore_create(1); #if SD_UIKIT + self.runLoopMode = [[self class] defaultRunLoopMode]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; #endif } - - (void)resetAnimatedImage { self.animatedImage = nil; @@ -269,25 +270,8 @@ dispatch_semaphore_signal(self->_lock); return; } - // Check Progressive coding - self.isProgressive = NO; - if ([image conformsToProtocol:@protocol(SDAnimatedImage)] && image.sd_isIncremental) { - NSData *currentData = [((UIImage *)image) animatedImageData]; - if (currentData) { - NSData *previousData; - if ([self.image conformsToProtocol:@protocol(SDAnimatedImage)]) { - previousData = [((UIImage *)self.image) animatedImageData]; - } - // Check whether to use progressive coding - if (!previousData) { - // If previous data is nil - self.isProgressive = YES; - } else if ([currentData isEqualToData:previousData]) { - // If current data is equal to previous data - self.isProgressive = YES; - } - } - } + // Check Progressive rendering + [self updateIsProgressiveWithImage:image]; if (self.isProgressive) { // Reset all value, but keep current state @@ -307,6 +291,10 @@ dispatch_semaphore_signal(self->_lock); if (animatedImageFrameCount <= 1) { return; } + // If progressive rendering is disabled but animated image is incremental. Only show poster image + if (!self.isProgressive && image.sd_isIncremental) { + return; + } self.animatedImage = (UIImage *)image; self.totalFrameCount = animatedImageFrameCount; // Get the current frame and loop count. @@ -346,6 +334,7 @@ dispatch_semaphore_signal(self->_lock); #endif } +#if SD_UIKIT - (void)setRunLoopMode:(NSString *)runLoopMode { if (![@[NSDefaultRunLoopMode, NSRunLoopCommonModes] containsObject:runLoopMode]) { @@ -355,6 +344,7 @@ dispatch_semaphore_signal(self->_lock); _runLoopMode = runLoopMode; } } +#endif #pragma mark - Private - (NSOperationQueue *)fetchQueue @@ -623,6 +613,33 @@ dispatch_semaphore_signal(self->_lock); self.shouldAnimate = self.animatedImage && self.totalFrameCount > 1 && isVisible; } +// Update progressive status only after `setImage:` call. +- (void)updateIsProgressiveWithImage:(UIImage *)image +{ + self.isProgressive = NO; + if (!self.shouldIncrementalLoad) { + // Early return + return; + } + if ([image conformsToProtocol:@protocol(SDAnimatedImage)] && image.sd_isIncremental) { + NSData *currentData = [((UIImage *)image) animatedImageData]; + if (currentData) { + NSData *previousData; + if ([self.image conformsToProtocol:@protocol(SDAnimatedImage)]) { + previousData = [((UIImage *)self.image) animatedImageData]; + } + // Check whether to use progressive coding + if (!previousData) { + // If previous data is nil + self.isProgressive = YES; + } else if ([currentData isEqualToData:previousData]) { + // If current data is equal to previous data + self.isProgressive = YES; + } + } + } +} + #if SD_MAC - (void)displayDidRefresh:(CVDisplayLinkRef)displayLink duration:(NSTimeInterval)duration #else @@ -735,8 +752,8 @@ dispatch_semaphore_signal(self->_lock); } -#pragma mark - CALayerDelegate (Informal) #pragma mark Providing the Layer's Content +#pragma mark - CALayerDelegate - (void)displayLayer:(CALayer *)layer { From f01fe38fdd99112a587120cd3ee9ad25d2778248 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 24 Mar 2018 00:15:27 +0800 Subject: [PATCH 096/361] Add downloader request modifier to allow modify final HTTP request. Also open the API to allow advanced user to check cache & downloader operation. --- SDWebImage/SDWebImageDefine.h | 5 ++ SDWebImage/SDWebImageDefine.m | 1 + SDWebImage/SDWebImageDownloader.h | 25 +++--- SDWebImage/SDWebImageDownloader.m | 90 ++++++++++++++-------- SDWebImage/SDWebImageDownloaderOperation.h | 5 -- SDWebImage/SDWebImageDownloaderOperation.m | 2 +- SDWebImage/SDWebImageManager.h | 42 +++++++--- SDWebImage/SDWebImageManager.m | 28 ++++--- SDWebImage/UIView+WebCacheOperation.h | 8 ++ SDWebImage/UIView+WebCacheOperation.m | 9 +++ Tests/Tests/SDWebImageDownloaderTests.m | 55 +++++++++++-- 11 files changed, 190 insertions(+), 80 deletions(-) diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index 2f2f6a8c..12151767 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -181,3 +181,8 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustom This can be used to improve animated images rendering performance (especially memory usage on big animated images) with `SDAnimatedImageView` (Class). */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextAnimatedImageClass; + +/** + A SDWebImageDownloaderRequestModifierBlock instance(dispatch_block_t) to modify the image download request. It's used for downloader to modify the original request from URL and options. If you provide one, it will ignore the `requestModifier` in downloader and use provided one instead. (SDWebImageDownloaderRequestModifierBlock) + */ +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextDownloadRequestModifier; diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m index 84f51da0..85026bf1 100644 --- a/SDWebImage/SDWebImageDefine.m +++ b/SDWebImage/SDWebImageDefine.m @@ -104,3 +104,4 @@ SDWebImageContextOption const SDWebImageContextSetImageGroup = @"setImageGroup"; SDWebImageContextOption const SDWebImageContextCustomManager = @"customManager"; SDWebImageContextOption const SDWebImageContextCustomTransformer = @"customTransformer"; SDWebImageContextOption const SDWebImageContextAnimatedImageClass = @"animatedImageClass"; +SDWebImageContextOption const SDWebImageContextDownloadRequestModifier = @"downloadRequestModifier"; diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index b5ff037b..5e69435b 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -81,10 +81,7 @@ typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteg typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished); -typedef NSDictionary SDHTTPHeadersDictionary; -typedef NSMutableDictionary SDHTTPHeadersMutableDictionary; - -typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterBlock)(NSURL * _Nullable url, SDHTTPHeadersDictionary * _Nullable headers); +typedef NSURLRequest * _Nullable (^SDWebImageDownloaderRequestModifierBlock)(NSURLRequest * _Nonnull request); /** * A token associated with each download. Can be used to cancel a download @@ -100,6 +97,10 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB The download's URL. */ @property (nonatomic, strong, nullable, readonly) NSURL *url; +/** + The doenload's response. + */ +@property (nonatomic, strong, nullable, readonly) NSURLResponse *response; @end @@ -116,12 +117,11 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB @property (nonatomic, copy, readonly, nonnull) SDWebImageDownloaderConfig *config; /** - * Set filter to pick headers for downloading image HTTP request. - * - * This block will be invoked for each downloading image request, returned - * NSDictionary will be used as headers in corresponding HTTP request. + * Set the request modifier to modify the original download request before image load. + * This block will be invoked for each downloading image request if provided. Return the original request means no modication. Return nil will cancel the download request. + * @note If you want to modify single request, consider using `SDWebImageContextDownloadRequestModifier` context option. */ -@property (nonatomic, copy, nullable) SDWebImageDownloaderHeadersFilterBlock headersFilter; +@property (nonatomic, copy, nullable) SDWebImageDownloaderRequestModifierBlock requestModifier; /** * The configuration in use by the internal NSURLSession. If you want to provide a custom sessionConfiguration, use `SDWebImageDownloaderConfig.sessionConfiguration` and create a new downloader instance. @@ -217,13 +217,6 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock; -/** - * Cancels a download that was previously queued using -downloadImageWithURL:options:progress:completed: - * - * @param token The token received from -downloadImageWithURL:options:progress:completed: that should be canceled. - */ -- (void)cancel:(nullable SDWebImageDownloadToken *)token; - /** * Cancels all download operations in the queue */ diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 1ccb2969..1bc1bf53 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -18,6 +18,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; @interface SDWebImageDownloadToken () @property (nonatomic, strong, nullable, readwrite) NSURL *url; +@property (nonatomic, strong, nullable, readwrite) NSURLResponse *response; @property (nonatomic, strong, nullable, readwrite) id downloadOperationCancelToken; @property (nonatomic, weak, nullable) NSOperation *downloadOperation; @property (nonatomic, weak, nullable) SDWebImageDownloader *downloader; @@ -25,15 +26,13 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; @end - @interface SDWebImageDownloader () @property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue; @property (weak, nonatomic, nullable) NSOperation *lastAddedOperation; @property (strong, nonatomic, nonnull) NSMutableDictionary *> *URLOperations; -@property (strong, nonatomic, nullable) SDHTTPHeadersMutableDictionary *HTTPHeaders; +@property (copy, atomic, nullable) NSDictionary *HTTPHeaders; // Since modify this value is rare, use immutable object can enhance performance. But should mark as atomic to keep thread-safe @property (strong, nonatomic, nonnull) dispatch_semaphore_t operationsLock; // a lock to keep the access to `URLOperations` thread-safe -@property (strong, nonatomic, nonnull) dispatch_semaphore_t headersLock; // a lock to keep the access to `HTTPHeaders` thread-safe // The session in which data tasks will run @property (strong, nonatomic) NSURLSession *session; @@ -91,12 +90,11 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; _downloadQueue.name = @"com.hackemist.SDWebImageDownloader"; _URLOperations = [NSMutableDictionary new]; #ifdef SD_WEBP - _HTTPHeaders = [@{@"Accept": @"image/webp,image/*;q=0.8"} mutableCopy]; + _HTTPHeaders = @{@"Accept": @"image/webp,image/*;q=0.8"}; #else - _HTTPHeaders = [@{@"Accept": @"image/*;q=0.8"} mutableCopy]; + _HTTPHeaders = @{@"Accept": @"image/*;q=0.8"}; #endif _operationsLock = dispatch_semaphore_create(1); - _headersLock = dispatch_semaphore_create(1); NSURLSessionConfiguration *sessionConfiguration = _config.sessionConfiguration; if (!sessionConfiguration) { sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; @@ -133,27 +131,20 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; } - (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field { - LOCK(self.headersLock); + NSMutableDictionary *mutableHTTPHeaders = [self.HTTPHeaders mutableCopy]; if (value) { - self.HTTPHeaders[field] = value; + [mutableHTTPHeaders setObject:value forKey:field]; } else { - [self.HTTPHeaders removeObjectForKey:field]; + [mutableHTTPHeaders removeObjectForKey:field]; } - UNLOCK(self.headersLock); + self.HTTPHeaders = [mutableHTTPHeaders copy]; } - (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field { if (!field) { return nil; } - return [[self allHTTPHeaderFields] objectForKey:field]; -} - -- (nonnull SDHTTPHeadersDictionary *)allHTTPHeaderFields { - LOCK(self.headersLock); - SDHTTPHeadersDictionary *allHTTPHeaderFields = [self.HTTPHeaders copy]; - UNLOCK(self.headersLock); - return allHTTPHeaderFields; + return [self.HTTPHeaders objectForKey:field]; } - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock { @@ -176,17 +167,28 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; // In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise NSURLRequestCachePolicy cachePolicy = options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData; - NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url - cachePolicy:cachePolicy - timeoutInterval:timeoutInterval]; - - request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies); - request.HTTPShouldUsePipelining = YES; - if (sself.headersFilter) { - request.allHTTPHeaderFields = sself.headersFilter(url, [sself allHTTPHeaderFields]); + NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:cachePolicy timeoutInterval:timeoutInterval]; + mutableRequest.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies); + mutableRequest.HTTPShouldUsePipelining = YES; + mutableRequest.allHTTPHeaderFields = sself.HTTPHeaders; + SDWebImageDownloaderRequestModifierBlock requestModifier; + if ([context valueForKey:SDWebImageContextDownloadRequestModifier]) { + requestModifier = [context valueForKey:SDWebImageContextDownloadRequestModifier]; + } else { + requestModifier = self.requestModifier; } - else { - request.allHTTPHeaderFields = [sself allHTTPHeaderFields]; + + NSURLRequest *request; + if (requestModifier) { + NSURLRequest *modifiedRequest = requestModifier([mutableRequest copy]); + // If modified request is nil, early return + if (!modifiedRequest) { + return nil; + } else { + request = [modifiedRequest copy]; + } + } else { + request = [mutableRequest copy]; } Class operationClass = sself.config.operationClass; if (operationClass && [operationClass isSubclassOfClass:[NSOperation class]] && [operationClass conformsToProtocol:@protocol(SDWebImageDownloaderOperation)]) { @@ -241,8 +243,9 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; createCallback:(NSOperation *(^)(void))createCallback { // The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data. if (url == nil) { - if (completedBlock != nil) { - completedBlock(nil, nil, nil, NO); + if (completedBlock) { + NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to download a nil url"}]; + completedBlock(nil, nil, error, YES); } return nil; } @@ -251,6 +254,14 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; NSOperation *operation = [self.URLOperations objectForKey:url]; if (!operation) { operation = createCallback(); + if (!operation) { + UNLOCK(self.operationsLock); + if (completedBlock) { + NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Downloader operation is nil"}]; + completedBlock(nil, nil, error, YES); + } + return nil; + } __weak typeof(self) wself = self; operation.completionBlock = ^{ __strong typeof(wself) sself = wself; @@ -412,6 +423,25 @@ didReceiveResponse:(NSURLResponse *)response @implementation SDWebImageDownloadToken +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self name:SDWebImageDownloadReceiveResponseNotification object:nil]; +} + +- (instancetype)init { + self = [super init]; + if (self) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadReceiveResponse:) name:SDWebImageDownloadReceiveResponseNotification object:nil]; + } + return self; +} + +- (void)downloadReceiveResponse:(NSNotification *)notification { + NSOperation *downloadOperation = notification.object; + if (downloadOperation && downloadOperation == self.downloadOperation) { + self.response = downloadOperation.response; + } +} + - (void)cancel { @synchronized (self) { if (self.isCancelled) { diff --git a/SDWebImage/SDWebImageDownloaderOperation.h b/SDWebImage/SDWebImageDownloaderOperation.h index 7c42a34f..2f776567 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.h +++ b/SDWebImage/SDWebImageDownloaderOperation.h @@ -93,11 +93,6 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification */ @property (copy, nonatomic, readonly, nullable) SDWebImageContext *context; -/** - * The expected size of data. - */ -@property (assign, nonatomic, readonly) NSInteger expectedSize; - /** * Initializes a `SDWebImageDownloaderOperation` object * diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 0d755b44..658e7337 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -46,7 +46,7 @@ typedef NSMutableDictionary SDCallbacksDictionary; @property (strong, nonatomic, nullable) NSMutableData *imageData; @property (copy, nonatomic, nullable) NSData *cachedData; // for `SDWebImageDownloaderIgnoreCachedResponse` @property (copy, nonatomic, nullable) NSString *cacheKey; -@property (assign, nonatomic, readwrite) NSInteger expectedSize; +@property (assign, nonatomic, readwrite) long long expectedSize; @property (strong, nonatomic, nullable, readwrite) NSURLResponse *response; // This is weak because it is injected by whoever manages this session. If this gets nil-ed out, we won't be able to run diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 08f467d1..e93353bb 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -20,6 +20,26 @@ typedef NSString * _Nullable(^SDWebImageCacheKeyFilterBlock)(NSURL * _Nullable u typedef NSData * _Nullable(^SDWebImageCacheSerializerBlock)(UIImage * _Nonnull image, NSData * _Nullable data, NSURL * _Nullable imageURL); +// A combined operation representing the cache and download operation. You can it to cancel the load process. +@interface SDWebImageCombinedOperation : NSObject + +/** + Cancel the current operation, including cache and download process + */ +- (void)cancel; + +/** + The cache operation used for image cache query + */ +@property (strong, nonatomic, nullable, readonly) id cacheOperation; + +/** + The download operation if the image is download from the network + */ +@property (strong, nonatomic, nullable, readonly) id downloadOperation; + +@end + @class SDWebImageManager; @@ -173,12 +193,12 @@ SDWebImageManager.sharedManager.cacheKeyFilter = ^(NSURL * _Nullable url) { * * The last parameter is the original image URL * - * @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation + * @return Returns an instance of SDWebImageCombinedOperation, which you can cancel the loading process. */ -- (nullable id )loadImageWithURL:(nullable NSURL *)url - options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nonnull SDInternalCompletionBlock)completedBlock; +- (nullable SDWebImageCombinedOperation *)loadImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nonnull SDInternalCompletionBlock)completedBlock; /** * Downloads the image at the given URL if not present in cache or return the cached version otherwise. @@ -190,13 +210,13 @@ SDWebImageManager.sharedManager.cacheKeyFilter = ^(NSURL * _Nullable url) { * @note the progress block is executed on a background queue * @param completedBlock A block called when operation has been completed. * - * @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation + * @return Returns an instance of SDWebImageCombinedOperation, which you can cancel the loading process. */ -- (nullable id )loadImageWithURL:(nullable NSURL *)url - options:(SDWebImageOptions)options - context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nonnull SDInternalCompletionBlock)completedBlock; +- (nullable SDWebImageCombinedOperation *)loadImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nonnull SDInternalCompletionBlock)completedBlock; /** * Saves image to cache for given URL diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 1fa92d5e..28276bad 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -11,11 +11,11 @@ #import "UIImage+WebCache.h" #import "SDAnimatedImage.h" -@interface SDWebImageCombinedOperation : NSObject +@interface SDWebImageCombinedOperation () @property (assign, nonatomic, getter = isCancelled) BOOL cancelled; -@property (strong, nonatomic, nullable) SDWebImageDownloadToken *downloadToken; -@property (strong, nonatomic, nullable) NSOperation *cacheOperation; +@property (strong, nonatomic, readwrite, nullable) id downloadOperation; +@property (strong, nonatomic, readwrite, nullable) id cacheOperation; @property (weak, nonatomic, nullable) SDWebImageManager *manager; @end @@ -108,15 +108,15 @@ }]; } -- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDInternalCompletionBlock)completedBlock { +- (SDWebImageCombinedOperation *)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDInternalCompletionBlock)completedBlock { return [self loadImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock]; } -- (id)loadImageWithURL:(nullable NSURL *)url - options:(SDWebImageOptions)options - context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nonnull SDInternalCompletionBlock)completedBlock { +- (SDWebImageCombinedOperation *)loadImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nonnull SDInternalCompletionBlock)completedBlock { // Invoking this method without a completedBlock is pointless NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead"); @@ -216,7 +216,7 @@ // `SDWebImageCombinedOperation` -> `SDWebImageDownloadToken` -> `downloadOperationCancelToken`, which is a `SDCallbacksDictionary` and retain the completed block below, so we need weak-strong again to avoid retain cycle __weak typeof(strongOperation) weakSubOperation = strongOperation; - strongOperation.downloadToken = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions context:context progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { + strongOperation.downloadOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions context:context progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { __strong typeof(weakSubOperation) strongSubOperation = weakSubOperation; if (!strongSubOperation || strongSubOperation.isCancelled) { // Do nothing if the operation was cancelled @@ -372,13 +372,17 @@ - (void)cancel { @synchronized(self) { + if (self.isCancelled) { + return; + } self.cancelled = YES; if (self.cacheOperation) { [self.cacheOperation cancel]; self.cacheOperation = nil; } - if (self.downloadToken) { - [self.manager.imageDownloader cancel:self.downloadToken]; + if (self.downloadOperation) { + [self.downloadOperation cancel]; + self.downloadOperation = nil; } [self.manager safelyRemoveOperationFromRunning:self]; } diff --git a/SDWebImage/UIView+WebCacheOperation.h b/SDWebImage/UIView+WebCacheOperation.h index 5d44691f..18361829 100644 --- a/SDWebImage/UIView+WebCacheOperation.h +++ b/SDWebImage/UIView+WebCacheOperation.h @@ -16,6 +16,14 @@ // All the stored operations are weak, so it will be dalloced after image loading finished. If you need to store operations, use your own class to keep a strong reference for them. @interface UIView (WebCacheOperation) +/** + * Get the image load operation for key + * + * @param key key for identifying the operations + * @return the image load operation + */ +- (nullable id)sd_imageLoadOperationForKey:(nullable NSString *)key; + /** * Set the image load operation (storage in a UIView based weak map table) * diff --git a/SDWebImage/UIView+WebCacheOperation.m b/SDWebImage/UIView+WebCacheOperation.m index 3d1329cf..b4f25edc 100644 --- a/SDWebImage/UIView+WebCacheOperation.m +++ b/SDWebImage/UIView+WebCacheOperation.m @@ -32,6 +32,15 @@ typedef NSMapTable> SDOperationsDictionary; } } +- (nullable id)sd_imageLoadOperationForKey:(nullable NSString *)key { + id operation; + SDOperationsDictionary *operationDictionary = [self sd_operationDictionary]; + @synchronized (self) { + operation = [operationDictionary objectForKey:key]; + } + return operation; +} + - (void)sd_setImageLoadOperation:(nullable id)operation forKey:(nullable NSString *)key { if (key) { [self sd_cancelImageLoadOperationWithKey:key]; diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index d06d633d..125d3137 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -109,10 +109,10 @@ - (void)test07ThatAddProgressCallbackCompletedBlockWithNilURLCallsTheCompletionBlockWithNils { XCTestExpectation *expectation = [self expectationWithDescription:@"Completion is called with nils"]; [[SDWebImageDownloader sharedDownloader] addProgressCallback:nil completedBlock:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { - if (!image && !data && !error) { + if (!image && !data && error) { [expectation fulfill]; } else { - XCTFail(@"All params should be nil"); + XCTFail(@"All params except error should be nil"); } } forURL:nil createCallback:nil]; [self waitForExpectationsWithTimeout:0.5 handler:nil]; @@ -174,7 +174,7 @@ }]; expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1); - [[SDWebImageDownloader sharedDownloader] cancel:token]; + [token cancel]; // doesn't cancel immediately - since it uses dispatch async dispatch_after(dispatch_time(DISPATCH_TIME_NOW, kMinDelayNanosecond), dispatch_get_main_queue(), ^{ @@ -298,7 +298,7 @@ }]; expect(token2).toNot.beNil(); - [[SDWebImageDownloader sharedDownloader] cancel:token1]; + [token1 cancel]; [self waitForExpectationsWithCommonTimeout]; } @@ -323,7 +323,7 @@ }]; expect(token1).toNot.beNil(); - [[SDWebImageDownloader sharedDownloader] cancel:token1]; + [token1 cancel]; SDWebImageDownloadToken *token2 = [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL @@ -369,4 +369,49 @@ } #endif +- (void)test23ThatDownloadRequestModifierWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Download request modifier not works"]; + SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] init]; + SDWebImageDownloaderRequestModifierBlock requestModifier = ^NSURLRequest *(NSURLRequest * request) { + if ([request.URL.absoluteString isEqualToString:kTestPNGURL]) { + // Test that return a modified request + NSMutableURLRequest *mutableRequest = [request mutableCopy]; + [mutableRequest setValue:@"Bar" forHTTPHeaderField:@"Foo"]; + NSURLComponents *components = [NSURLComponents componentsWithURL:mutableRequest.URL resolvingAgainstBaseURL:NO]; + components.query = @"text=Hello+World"; + mutableRequest.URL = components.URL; + return mutableRequest; + } else if ([request.URL.absoluteString isEqualToString:kTestJpegURL]) { + // Test that return nil request will treat as error + return nil; + } else { + return request; + } + }; + downloader.requestModifier = requestModifier; + + __block BOOL firstCheck = NO; + __block BOOL secondCheck = NO; + + [downloader downloadImageWithURL:[NSURL URLWithString:kTestJpegURL] options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + // Except error + expect(error).notTo.beNil(); + firstCheck = YES; + if (firstCheck && secondCheck) { + [expectation fulfill]; + } + }]; + + [downloader downloadImageWithURL:[NSURL URLWithString:kTestPNGURL] options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + // Expect not error + expect(error).to.beNil(); + secondCheck = YES; + if (firstCheck && secondCheck) { + [expectation fulfill]; + } + }]; + + [self waitForExpectationsWithCommonTimeout]; +} + @end From fa7d19c099764a27f58fef80ec7c36e90e529a69 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 5 Apr 2018 16:22:58 +0800 Subject: [PATCH 097/361] Update the comments and expose the token's request, which can be used for advanced usage. --- SDWebImage/SDWebImageDownloader.h | 14 ++++++++++---- SDWebImage/SDWebImageDownloader.m | 4 +++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 5e69435b..17b725b7 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -97,10 +97,16 @@ typedef NSURLRequest * _Nullable (^SDWebImageDownloaderRequestModifierBlock)(NSU The download's URL. */ @property (nonatomic, strong, nullable, readonly) NSURL *url; + /** - The doenload's response. + The download's request. */ -@property (nonatomic, strong, nullable, readonly) NSURLResponse *response; +@property (nonatomic, copy, nullable, readonly) NSURLRequest *request; + +/** + The download's response. + */ +@property (nonatomic, copy, nullable, readonly) NSURLResponse *response; @end @@ -188,7 +194,7 @@ typedef NSURLRequest * _Nullable (^SDWebImageDownloaderRequestModifierBlock)(NSU * before to be called a last time with the full image and finished argument * set to YES. In case of error, the finished argument is always YES. * - * @return A token (SDWebImageDownloadToken) that can be passed to -cancel: to cancel this operation + * @return A token (SDWebImageDownloadToken) that can be used to cancel this operation */ - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url options:(SDWebImageDownloaderOptions)options @@ -209,7 +215,7 @@ typedef NSURLRequest * _Nullable (^SDWebImageDownloaderRequestModifierBlock)(NSU * @note the progress block is executed on a background queue * @param completedBlock A block called once the download is completed. * - * @return A token (SDWebImageDownloadToken) that can be passed to -cancel: to cancel this operation + * @return A token (SDWebImageDownloadToken) that can be used to cancel this operation */ - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url options:(SDWebImageDownloaderOptions)options diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 1bc1bf53..20583ade 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -18,7 +18,8 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; @interface SDWebImageDownloadToken () @property (nonatomic, strong, nullable, readwrite) NSURL *url; -@property (nonatomic, strong, nullable, readwrite) NSURLResponse *response; +@property (nonatomic, copy, nullable, readwrite) NSURLRequest *request; +@property (nonatomic, copy, nullable, readwrite) NSURLResponse *response; @property (nonatomic, strong, nullable, readwrite) id downloadOperationCancelToken; @property (nonatomic, weak, nullable) NSOperation *downloadOperation; @property (nonatomic, weak, nullable) SDWebImageDownloader *downloader; @@ -284,6 +285,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; SDWebImageDownloadToken *token = [SDWebImageDownloadToken new]; token.downloadOperation = operation; token.url = url; + token.request = operation.request; token.downloadOperationCancelToken = downloadOperationCancelToken; token.downloader = self; From 55256d00913db4836fae82700b348399545b3989 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 7 Apr 2018 13:47:54 +0800 Subject: [PATCH 098/361] Use a protocol instance instead of block for request modifier. This can solve the problem that Swift user is hard to grab the block back stored in dictionary. --- SDWebImage.xcodeproj/project.pbxproj | 28 +++++++++++++ SDWebImage/SDWebImageDefine.h | 2 +- SDWebImage/SDWebImageDownloader.h | 8 ++-- SDWebImage/SDWebImageDownloader.m | 4 +- .../SDWebImageDownloaderRequestModifier.h | 25 ++++++++++++ .../SDWebImageDownloaderRequestModifier.m | 39 +++++++++++++++++++ Tests/Tests/SDWebImageDownloaderTests.m | 4 +- WebImage/SDWebImage.h | 1 + 8 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 SDWebImage/SDWebImageDownloaderRequestModifier.h create mode 100644 SDWebImage/SDWebImageDownloaderRequestModifier.m diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 4760c2d7..a718aecd 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -453,6 +453,18 @@ 32EB6D90206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; 32EB6D91206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; 32EB6D92206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; + 32F21B5120788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F21B5220788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F21B5320788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F21B5420788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F21B5520788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F21B5620788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F21B5720788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; + 32F21B5820788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; + 32F21B5920788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; + 32F21B5A20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; + 32F21B5B20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; + 32F21B5C20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; 32F7C06F2030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32F7C0702030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32F7C0712030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1490,6 +1502,8 @@ 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageIndicator.m; sourceTree = ""; }; 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoderHelper.h; sourceTree = ""; }; 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCoderHelper.m; sourceTree = ""; }; + 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderRequestModifier.h; sourceTree = ""; }; + 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderRequestModifier.m; sourceTree = ""; }; 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTransformer.h; sourceTree = ""; }; 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransformer.m; sourceTree = ""; }; 32F7C07C2030719600873181 /* UIImage+Transform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Transform.m"; sourceTree = ""; }; @@ -1984,6 +1998,8 @@ 530E49E416460AE2002868E7 /* SDWebImageDownloaderOperation.m */, 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */, 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */, + 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */, + 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */, ); name = Downloader; sourceTree = ""; @@ -2196,6 +2212,7 @@ 323F8BE71F38EF770092B609 /* vp8li_enc.h in Headers */, 329A185C1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 4369C27A1D9807EC007E863A /* UIView+WebCache.h in Headers */, + 32F21B5420788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 80377DCC1F2F66A700F89830 /* lossless_common.h in Headers */, 321E60971F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, 43A918671D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, @@ -2332,6 +2349,7 @@ 80377C191F2F666300F89830 /* endian_inl_utils.h in Headers */, 321E60A31F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, 4314D17C1D0E0E3B004B36C9 /* UIImage+WebP.h in Headers */, + 32F21B5220788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 4369C2781D9807EC007E863A /* UIView+WebCache.h in Headers */, 80377D621F2F66A700F89830 /* yuv.h in Headers */, 80377D341F2F66A700F89830 /* dsp.h in Headers */, @@ -2427,6 +2445,7 @@ 43A62A1E1D0E0A800089D7DD /* format_constants.h in Headers */, 80377E111F2F66A800F89830 /* lossless_common.h in Headers */, 431BB6F61D06D2C1006A3455 /* UIImage+MultiFormat.h in Headers */, + 32F21B5520788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 807A122C1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, 323F8BFA1F38EF770092B609 /* animi.h in Headers */, 431BB6F91D06D2C1006A3455 /* UIImage+GIF.h in Headers */, @@ -2460,6 +2479,7 @@ 4397D2BD1D0DDD8C00BB2784 /* types.h in Headers */, 4397D2C01D0DDD8C00BB2784 /* SDWebImage.h in Headers */, 4397D2C11D0DDD8C00BB2784 /* format_constants.h in Headers */, + 32F21B5620788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 80377C8D1F2F666400F89830 /* random_utils.h in Headers */, 4397D2C31D0DDD8C00BB2784 /* SDWebImageManager.h in Headers */, 323F8B551F38EF770092B609 /* backward_references_enc.h in Headers */, @@ -2551,6 +2571,7 @@ 323F8BE61F38EF770092B609 /* vp8li_enc.h in Headers */, 329A185B1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 4369C2791D9807EC007E863A /* UIView+WebCache.h in Headers */, + 32F21B5320788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 80377D871F2F66A700F89830 /* lossless_common.h in Headers */, 321E60961F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, 4A2CAE041AB4BB5400B6BC39 /* SDWebImage.h in Headers */, @@ -2663,6 +2684,7 @@ 5376131A155AD0D5005750A4 /* SDWebImageDownloader.h in Headers */, 4369C2771D9807EC007E863A /* UIView+WebCache.h in Headers */, 80377CEF1F2F66A100F89830 /* dsp.h in Headers */, + 32F21B5120788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 80377C011F2F665300F89830 /* filters_utils.h in Headers */, 5376131C155AD0D5005750A4 /* SDWebImageManager.h in Headers */, 438096741CDFC09C00DC626B /* UIImage+WebP.h in Headers */, @@ -2977,6 +2999,7 @@ 80377DEB1F2F66A700F89830 /* yuv.c in Sources */, 3237F9E920161AE000A88143 /* NSImage+Additions.m in Sources */, 32C0FDEA2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, + 32F21B5A20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 00733A551BC4880000A5A117 /* SDWebImageDownloader.m in Sources */, 80377EB71F2F66D400F89830 /* alpha_dec.c in Sources */, 80377DC61F2F66A700F89830 /* enc.c in Sources */, @@ -3165,6 +3188,7 @@ 80377D5F1F2F66A700F89830 /* yuv_mips32.c in Sources */, 80377D3C1F2F66A700F89830 /* enc.c in Sources */, 4314D13B1D0E0E3B004B36C9 /* UIButton+WebCache.m in Sources */, + 32F21B5820788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 321E60C51F38E91700405457 /* UIImage+ForceDecode.m in Sources */, 80377D461F2F66A700F89830 /* lossless_enc_neon.c in Sources */, 80377E9B1F2F66D400F89830 /* frame_dec.c in Sources */, @@ -3321,6 +3345,7 @@ 80377E2E1F2F66A800F89830 /* yuv_mips32.c in Sources */, 80377E0B1F2F66A800F89830 /* enc.c in Sources */, 431BB6AC1D06D2C1006A3455 /* SDWebImageCompat.m in Sources */, + 32F21B5B20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 80377E151F2F66A800F89830 /* lossless_enc_neon.c in Sources */, 321E60C81F38E91700405457 /* UIImage+ForceDecode.m in Sources */, 80377C721F2F666400F89830 /* random_utils.c in Sources */, @@ -3475,6 +3500,7 @@ 323F8BF51F38EF770092B609 /* anim_encode.c in Sources */, 80377E381F2F66A800F89830 /* argb_sse2.c in Sources */, 323F8B9B1F38EF770092B609 /* near_lossless_enc.c in Sources */, + 32F21B5C20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 80377E3B1F2F66A800F89830 /* cost_mips_dsp_r2.c in Sources */, 4397D29B1D0DDD8C00BB2784 /* SDWebImageDownloader.m in Sources */, 80377E711F2F66A800F89830 /* upsampling.c in Sources */, @@ -3607,6 +3633,7 @@ 43CE757A1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, 3237F9E820161AE000A88143 /* NSImage+Additions.m in Sources */, 32C0FDE92013426C001B8F2D /* SDWebImageIndicator.m in Sources */, + 32F21B5920788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 80377D811F2F66A700F89830 /* enc.c in Sources */, 80377EA71F2F66D400F89830 /* alpha_dec.c in Sources */, 80377D8F1F2F66A700F89830 /* lossless_mips_dsp_r2.c in Sources */, @@ -3767,6 +3794,7 @@ 80377CF71F2F66A100F89830 /* enc.c in Sources */, 3237F9EB20161AE000A88143 /* NSImage+Additions.m in Sources */, 32C0FDE72013426C001B8F2D /* SDWebImageIndicator.m in Sources */, + 32F21B5720788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 80377E871F2F66D000F89830 /* alpha_dec.c in Sources */, 80377D051F2F66A100F89830 /* lossless_mips_dsp_r2.c in Sources */, 80377C0A1F2F665300F89830 /* random_utils.c in Sources */, diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index 12151767..0c3390d8 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -183,6 +183,6 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustom FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextAnimatedImageClass; /** - A SDWebImageDownloaderRequestModifierBlock instance(dispatch_block_t) to modify the image download request. It's used for downloader to modify the original request from URL and options. If you provide one, it will ignore the `requestModifier` in downloader and use provided one instead. (SDWebImageDownloaderRequestModifierBlock) + A id instance to modify the image download request. It's used for downloader to modify the original request from URL and options. If you provide one, it will ignore the `requestModifier` in downloader and use provided one instead. (id) */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextDownloadRequestModifier; diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 17b725b7..4cd42ea5 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -11,6 +11,7 @@ #import "SDWebImageDefine.h" #import "SDWebImageOperation.h" #import "SDWebImageDownloaderConfig.h" +#import "SDWebImageDownloaderRequestModifier.h" typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { /** @@ -81,8 +82,6 @@ typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteg typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished); -typedef NSURLRequest * _Nullable (^SDWebImageDownloaderRequestModifierBlock)(NSURLRequest * _Nonnull request); - /** * A token associated with each download. Can be used to cancel a download */ @@ -124,10 +123,11 @@ typedef NSURLRequest * _Nullable (^SDWebImageDownloaderRequestModifierBlock)(NSU /** * Set the request modifier to modify the original download request before image load. - * This block will be invoked for each downloading image request if provided. Return the original request means no modication. Return nil will cancel the download request. + * This request modifier method will be called for each downloading image request. Return the original request means no modication. Return nil will cancel the download request. + * Defaults to nil, means does not modify the original download request. * @note If you want to modify single request, consider using `SDWebImageContextDownloadRequestModifier` context option. */ -@property (nonatomic, copy, nullable) SDWebImageDownloaderRequestModifierBlock requestModifier; +@property (nonatomic, strong, nullable) id requestModifier; /** * The configuration in use by the internal NSURLSession. If you want to provide a custom sessionConfiguration, use `SDWebImageDownloaderConfig.sessionConfiguration` and create a new downloader instance. diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 20583ade..562d8979 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -172,7 +172,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; mutableRequest.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies); mutableRequest.HTTPShouldUsePipelining = YES; mutableRequest.allHTTPHeaderFields = sself.HTTPHeaders; - SDWebImageDownloaderRequestModifierBlock requestModifier; + id requestModifier; if ([context valueForKey:SDWebImageContextDownloadRequestModifier]) { requestModifier = [context valueForKey:SDWebImageContextDownloadRequestModifier]; } else { @@ -181,7 +181,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; NSURLRequest *request; if (requestModifier) { - NSURLRequest *modifiedRequest = requestModifier([mutableRequest copy]); + NSURLRequest *modifiedRequest = [requestModifier modifiedRequestWithRequest:[mutableRequest copy]]; // If modified request is nil, early return if (!modifiedRequest) { return nil; diff --git a/SDWebImage/SDWebImageDownloaderRequestModifier.h b/SDWebImage/SDWebImageDownloaderRequestModifier.h new file mode 100644 index 00000000..1c31db92 --- /dev/null +++ b/SDWebImage/SDWebImageDownloaderRequestModifier.h @@ -0,0 +1,25 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" + +typedef NSURLRequest * _Nullable (^SDWebImageDownloaderRequestModifierBlock)(NSURLRequest * _Nonnull request); + +@protocol SDWebImageDownloaderRequestModifier + +- (nullable NSURLRequest *)modifiedRequestWithRequest:(nonnull NSURLRequest *)request; + +@end + +@interface SDWebImageDownloaderRequestModifier : NSObject + +- (nonnull instancetype)initWithBlock:(nonnull SDWebImageDownloaderRequestModifierBlock)block; ++ (nonnull instancetype)requestModifierWithBlock:(nonnull SDWebImageDownloaderRequestModifierBlock)block; + +@end diff --git a/SDWebImage/SDWebImageDownloaderRequestModifier.m b/SDWebImage/SDWebImageDownloaderRequestModifier.m new file mode 100644 index 00000000..22d044af --- /dev/null +++ b/SDWebImage/SDWebImageDownloaderRequestModifier.m @@ -0,0 +1,39 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageDownloaderRequestModifier.h" + +@interface SDWebImageDownloaderRequestModifier () + +@property (nonatomic, copy, nonnull) SDWebImageDownloaderRequestModifierBlock block; + +@end + +@implementation SDWebImageDownloaderRequestModifier + +- (instancetype)initWithBlock:(SDWebImageDownloaderRequestModifierBlock)block { + self = [super init]; + if (self) { + self.block = block; + } + return self; +} + ++ (instancetype)requestModifierWithBlock:(SDWebImageDownloaderRequestModifierBlock)block { + SDWebImageDownloaderRequestModifier *requestModifier = [[SDWebImageDownloaderRequestModifier alloc] initWithBlock:block]; + return requestModifier; +} + +- (NSURLRequest *)modifiedRequestWithRequest:(NSURLRequest *)request { + if (!self.block) { + return nil; + } + return self.block(request); +} + +@end diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index 125d3137..c47550dc 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -372,7 +372,7 @@ - (void)test23ThatDownloadRequestModifierWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Download request modifier not works"]; SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] init]; - SDWebImageDownloaderRequestModifierBlock requestModifier = ^NSURLRequest *(NSURLRequest * request) { + SDWebImageDownloaderRequestModifier *requestModifier = [SDWebImageDownloaderRequestModifier requestModifierWithBlock:^NSURLRequest * _Nullable(NSURLRequest * _Nonnull request) { if ([request.URL.absoluteString isEqualToString:kTestPNGURL]) { // Test that return a modified request NSMutableURLRequest *mutableRequest = [request mutableCopy]; @@ -387,7 +387,7 @@ } else { return request; } - }; + }]; downloader.requestModifier = requestModifier; __block BOOL firstCheck = NO; diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index c6c4fb3b..087c9ca2 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -29,6 +29,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import +#import #import #import #import From fea3a56d71ec8b65ee437d64abc599b5133d951b Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 7 Apr 2018 23:21:16 +0800 Subject: [PATCH 099/361] Add a SDWebImageCoderDecodeScaleFactor option to specify scale factor using for decoder. Since the scale information is not stored into image data itself, but generated from image file name & metadata. --- SDWebImage/SDWebImageAPNGCoder.m | 10 ++- SDWebImage/SDWebImageCoder.h | 4 ++ SDWebImage/SDWebImageCoder.m | 1 + SDWebImage/SDWebImageGIFCoder.m | 8 ++- SDWebImage/SDWebImageImageIOCoder.m | 9 ++- SDWebImage/SDWebImageWebPCoder.m | 94 ++++++++++++++++++++--------- 6 files changed, 89 insertions(+), 37 deletions(-) diff --git a/SDWebImage/SDWebImageAPNGCoder.m b/SDWebImage/SDWebImageAPNGCoder.m index cbf261a9..ddbb45f8 100644 --- a/SDWebImage/SDWebImageAPNGCoder.m +++ b/SDWebImage/SDWebImageAPNGCoder.m @@ -95,11 +95,15 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef return nil; } size_t count = CGImageSourceGetCount(source); - + CGFloat scale = 1.0; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + scale = MAX(1.0, scale); + } UIImage *animatedImage; if (count <= 1) { - animatedImage = [[UIImage alloc] initWithData:data]; + animatedImage = [[UIImage alloc] initWithData:data scale:scale]; } else { NSMutableArray *frames = [NSMutableArray array]; @@ -110,7 +114,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef } float duration = [self sd_frameDurationAtIndex:i source:source]; - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef]; + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; CGImageRelease(imageRef); SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:image duration:duration]; diff --git a/SDWebImage/SDWebImageCoder.h b/SDWebImage/SDWebImageCoder.h index 1afe6757..22fbe61e 100644 --- a/SDWebImage/SDWebImageCoder.h +++ b/SDWebImage/SDWebImageCoder.h @@ -17,6 +17,10 @@ typedef NSDictionary SDWebImageCoderOptions; A Boolean value indicating whether to decode the first frame only for animated image during decoding. (NSNumber) */ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderDecodeFirstFrameOnly; +/** + A CGFloat value which is greater than or equal to 1.0. This value specify the image scale factor for decoding. If not provide, use 1.0. (NSNumber) + */ +FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderDecodeScaleFactor; /** A double value between 0.0-1.0 indicating the encode compression quality to produce the image data. If not provide, use 1.0. (NSNumber) */ diff --git a/SDWebImage/SDWebImageCoder.m b/SDWebImage/SDWebImageCoder.m index e5d82070..c7efce68 100644 --- a/SDWebImage/SDWebImageCoder.m +++ b/SDWebImage/SDWebImageCoder.m @@ -9,4 +9,5 @@ #import "SDWebImageCoder.h" SDWebImageCoderOption const SDWebImageCoderDecodeFirstFrameOnly = @"decodeFirstFrameOnly"; +SDWebImageCoderOption const SDWebImageCoderDecodeScaleFactor = @"decodeScaleFactor"; SDWebImageCoderOption const SDWebImageCoderEncodeCompressionQuality = @"encodeCompressionQuality"; diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index cfe2d207..71d66d3f 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -85,7 +85,11 @@ return nil; } size_t count = CGImageSourceGetCount(source); - + CGFloat scale = 1.0; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + scale = MAX(1.0, scale); + } UIImage *animatedImage; BOOL decodeFirstFrame = [options[SDWebImageCoderDecodeFirstFrameOnly] boolValue]; @@ -101,7 +105,7 @@ } float duration = [self sd_frameDurationAtIndex:i source:source]; - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef]; + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; CGImageRelease(imageRef); SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:image duration:duration]; diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index 0dd5a381..afb3387a 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -82,11 +82,16 @@ return nil; } - UIImage *image = [[UIImage alloc] initWithData:data]; - #if SD_MAC + UIImage *image = [[UIImage alloc] initWithData:data]; return image; #else + CGFloat scale = 1.0; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + scale = MAX(1.0, scale); + } + UIImage *image = [[UIImage alloc] initWithData:data scale:scale]; if (!image) { return nil; } diff --git a/SDWebImage/SDWebImageWebPCoder.m b/SDWebImage/SDWebImageWebPCoder.m index cf295292..bddf19d1 100644 --- a/SDWebImage/SDWebImageWebPCoder.m +++ b/SDWebImage/SDWebImageWebPCoder.m @@ -114,9 +114,25 @@ dispatch_semaphore_signal(self->_lock); uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS); BOOL hasAnimation = flags & ANIMATION_FLAG; BOOL decodeFirstFrame = [[options valueForKey:SDWebImageCoderDecodeFirstFrameOnly] boolValue]; +#if SD_UIKIT || SD_WATCH + CGFloat scale = 1.0; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + scale = MAX(1.0, scale); + } +#endif if (!hasAnimation) { // for static single webp image - UIImage *staticImage = [self sd_rawWebpImageWithData:webpData]; + CGImageRef imageRef = [self sd_createWebpImageWithData:webpData]; + if (!imageRef) { + return nil; + } +#if SD_UIKIT || SD_WATCH + UIImage *staticImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; +#else + UIImage *staticImage = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; +#endif + CGImageRelease(imageRef); WebPDemuxDelete(demuxer); return staticImage; } @@ -132,7 +148,13 @@ dispatch_semaphore_signal(self->_lock); if (decodeFirstFrame) { // first frame for animated webp image - UIImage *firstFrameImage = [self sd_rawWebpImageWithData:iter.fragment]; + CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment]; +#if SD_UIKIT || SD_WATCH + UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; +#else + UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; +#endif + CGImageRelease(imageRef); WebPDemuxReleaseIterator(&iter); WebPDemuxDelete(demuxer); return firstFrameImage; @@ -154,10 +176,16 @@ dispatch_semaphore_signal(self->_lock); do { @autoreleasepool { - UIImage *image = [self sd_drawnWebpImageWithCanvas:canvas iterator:iter]; - if (!image) { + CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:canvas iterator:iter]; + if (!imageRef) { continue; } +#if SD_UIKIT || SD_WATCH + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; +#else + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; +#endif + CGImageRelease(imageRef); NSTimeInterval duration = [self sd_frameDurationWithIterator:iter]; SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:image duration:duration]; @@ -271,8 +299,8 @@ dispatch_semaphore_signal(self->_lock); if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { CGContextClearRect(canvas, imageRect); } else { - UIImage *image = [self sd_rawWebpImageWithData:iter.fragment]; - if (!image) { + CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment]; + if (!imageRef) { return; } BOOL shouldBlend = iter.blend_method == WEBP_MUX_BLEND; @@ -280,13 +308,14 @@ dispatch_semaphore_signal(self->_lock); if (!shouldBlend) { CGContextClearRect(canvas, imageRect); } - CGContextDrawImage(canvas, imageRect, image.CGImage); + CGContextDrawImage(canvas, imageRect, imageRef); + CGImageRelease(imageRef); } } -- (nullable UIImage *)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter { - UIImage *image = [self sd_rawWebpImageWithData:iter.fragment]; - if (!image) { +- (nullable CGImageRef)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter CF_RETURNS_RETAINED { + CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment]; + if (!imageRef) { return nil; } @@ -300,25 +329,19 @@ dispatch_semaphore_signal(self->_lock); if (!shouldBlend) { CGContextClearRect(canvas, imageRect); } - CGContextDrawImage(canvas, imageRect, image.CGImage); + CGContextDrawImage(canvas, imageRect, imageRef); CGImageRef newImageRef = CGBitmapContextCreateImage(canvas); -#if SD_UIKIT || SD_WATCH - image = [[UIImage alloc] initWithCGImage:newImageRef]; -#elif SD_MAC - image = [[UIImage alloc] initWithCGImage:newImageRef size:NSZeroSize]; -#endif - - CGImageRelease(newImageRef); + CGImageRelease(imageRef); if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { CGContextClearRect(canvas, imageRect); } - return image; + return newImageRef; } -- (nullable UIImage *)sd_rawWebpImageWithData:(WebPData)webpData { +- (nullable CGImageRef)sd_createWebpImageWithData:(WebPData)webpData CF_RETURNS_RETAINED { WebPDecoderConfig config; if (!WebPInitDecoderConfig(&config)) { return nil; @@ -361,14 +384,7 @@ dispatch_semaphore_signal(self->_lock); CGDataProviderRelease(provider); -#if SD_UIKIT || SD_WATCH - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef]; -#else - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; -#endif - CGImageRelease(imageRef); - - return image; + return imageRef; } - (NSTimeInterval)sd_frameDurationWithIterator:(WebPIterator)iter { @@ -639,7 +655,16 @@ static void FreeImageData(void *info, const void *data, size_t size) { WebPDemuxReleaseIterator(&iter); return nil; } - image = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter]; + CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter]; + if (!imageRef) { + return nil; + } +#if SD_UIKIT || SD_WATCH + image = [[UIImage alloc] initWithCGImage:imageRef]; +#else + image = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; +#endif + CGImageRelease(imageRef); } else { // Else, this can happen when one image set to different imageViews or one loop end. So we should clear the shared cavans. if (_currentBlendIndex != NSNotFound) { @@ -660,7 +685,16 @@ static void FreeImageData(void *info, const void *data, size_t size) { if ((size_t)iter.frame_num == endIndex) { [self sd_blendWebpImageWithCanvas:_canvas iterator:iter]; } else { - image = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter]; + CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter]; + if (!imageRef) { + return nil; + } +#if SD_UIKIT || SD_WATCH + image = [[UIImage alloc] initWithCGImage:imageRef]; +#else + image = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; +#endif + CGImageRelease(imageRef); } } } while ((size_t)iter.frame_num < (endIndex + 1) && WebPDemuxNextFrame(&iter)); From 7a84e59eb11b6e6b50514607781869364d27983e Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 7 Apr 2018 23:22:25 +0800 Subject: [PATCH 100/361] Add the context option SDWebImageContextImageScaleFactor to custom a scale factor which is not based on the cache key. --- SDWebImage/SDImageCache.m | 9 ++----- SDWebImage/SDWebImageAPNGCoder.m | 6 +++-- SDWebImage/SDWebImageDefine.h | 5 ++++ SDWebImage/SDWebImageDefine.m | 1 + SDWebImage/SDWebImageDownloaderOperation.m | 30 +++++++++++----------- SDWebImage/SDWebImageGIFCoder.m | 6 +++-- SDWebImage/SDWebImageImageIOCoder.m | 6 +++-- SDWebImage/SDWebImageWebPCoder.m | 6 +++-- 8 files changed, 39 insertions(+), 30 deletions(-) diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index aac09322..7505da15 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -485,12 +485,12 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (data) { UIImage *image; BOOL decodeFirstFrame = options & SDImageCacheDecodeFirstFrameOnly; + CGFloat scale = [context valueForKey:SDWebImageContextImageScaleFactor] ? [[context valueForKey:SDWebImageContextImageScaleFactor] doubleValue] : SDImageScaleForKey(key); if (!decodeFirstFrame) { // check whether we should use `SDAnimatedImage` if ([context valueForKey:SDWebImageContextAnimatedImageClass]) { Class animatedImageClass = [context valueForKey:SDWebImageContextAnimatedImageClass]; if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { - CGFloat scale = SDImageScaleForKey(key); image = [[animatedImageClass alloc] initWithData:data scale:scale]; if (options & SDImageCachePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { [((id)image) preloadAllFrames]; @@ -499,8 +499,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } } if (!image) { - image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame)}]; - image = [self scaledImageForKey:key image:image]; + image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageContextImageScaleFactor : @(scale)}]; } BOOL shouldDecode = YES; if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { @@ -521,10 +520,6 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } } -- (nullable UIImage *)scaledImageForKey:(nullable NSString *)key image:(nullable UIImage *)image { - return SDScaledImageForKey(key, image); -} - - (nullable NSOperation *)queryCacheOperationForKey:(NSString *)key done:(SDCacheQueryCompletedBlock)doneBlock { return [self queryCacheOperationForKey:key options:0 done:doneBlock]; } diff --git a/SDWebImage/SDWebImageAPNGCoder.m b/SDWebImage/SDWebImageAPNGCoder.m index ddbb45f8..be729350 100644 --- a/SDWebImage/SDWebImageAPNGCoder.m +++ b/SDWebImage/SDWebImageAPNGCoder.m @@ -95,10 +95,12 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef return nil; } size_t count = CGImageSourceGetCount(source); - CGFloat scale = 1.0; + CGFloat scale = 1; if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; - scale = MAX(1.0, scale); + if (scale < 1) { + scale = 1; + } } UIImage *animatedImage; diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index 2f2f6a8c..a6e70b1f 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -176,6 +176,11 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustom */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustomTransformer; +/** + A CGFloat value which specify the image scale factor. The number should be greater than or equal to 1.0. If not provide or the number is invalid, we will use the cache key to specify the scale factor. (NSNumber) + */ +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageScaleFactor; + /** A Class object which the instance is a `UIImage/NSImage` subclass and adopt `SDAnimatedImage` protocol. We will call `initWithData:scale:` to create the instance (or `initWithAnimatedCoder:scale` when using progressive download) . If the instance create failed, fallback to normal `UIImage/NSImage`. This can be used to improve animated images rendering performance (especially memory usage on big animated images) with `SDAnimatedImageView` (Class). diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m index 84f51da0..41da36e4 100644 --- a/SDWebImage/SDWebImageDefine.m +++ b/SDWebImage/SDWebImageDefine.m @@ -103,4 +103,5 @@ SDWebImageContextOption const SDWebImageContextSetImageOperationKey = @"setImage SDWebImageContextOption const SDWebImageContextSetImageGroup = @"setImageGroup"; SDWebImageContextOption const SDWebImageContextCustomManager = @"customManager"; SDWebImageContextOption const SDWebImageContextCustomTransformer = @"customTransformer"; +SDWebImageContextOption const SDWebImageContextImageScaleFactor = @"imageScaleFactor"; SDWebImageContextOption const SDWebImageContextAnimatedImageClass = @"animatedImageClass"; diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 0d755b44..87dc7e3e 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -363,17 +363,19 @@ didReceiveResponse:(NSURLResponse *)response dispatch_async(self.coderQueue, ^{ // check whether we should use `SDAnimatedImage` UIImage *image; - if ([self.context valueForKey:SDWebImageContextAnimatedImageClass]) { - Class animatedImageClass = [self.context valueForKey:SDWebImageContextAnimatedImageClass]; - if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)] && [self.progressiveCoder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { - CGFloat scale = SDImageScaleForKey(self.cacheKey); - image = [[animatedImageClass alloc] initWithAnimatedCoder:(id)self.progressiveCoder scale:scale]; + BOOL decodeFirstFrame = self.options & SDWebImageDownloaderDecodeFirstFrameOnly; + CGFloat scale = [self.context valueForKey:SDWebImageContextImageScaleFactor] ? [[self.context valueForKey:SDWebImageContextImageScaleFactor] doubleValue] : SDImageScaleForKey(self.cacheKey); + if (!decodeFirstFrame) { + // check whether we should use `SDAnimatedImage` + if ([self.context valueForKey:SDWebImageContextAnimatedImageClass]) { + Class animatedImageClass = [self.context valueForKey:SDWebImageContextAnimatedImageClass]; + if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)] && [self.progressiveCoder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { + image = [[animatedImageClass alloc] initWithAnimatedCoder:(id)self.progressiveCoder scale:scale]; + } } } if (!image) { - BOOL decodeFirstFrame = self.options & SDWebImageDownloaderDecodeFirstFrameOnly; - image = [self.progressiveCoder incrementalDecodedImageWithOptions:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame)}]; - image = [self scaledImageForKey:self.cacheKey image:image]; + image = [self.progressiveCoder incrementalDecodedImageWithOptions:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageContextImageScaleFactor : @(scale)}]; } if (image) { BOOL shouldDecode = self.shouldDecompressImages; @@ -454,13 +456,16 @@ didReceiveResponse:(NSURLResponse *)response // decode the image in coder queue dispatch_async(self.coderQueue, ^{ BOOL decodeFirstFrame = self.options & SDWebImageDownloaderDecodeFirstFrameOnly; + CGFloat scale = [self.context valueForKey:SDWebImageContextImageScaleFactor] ? [[self.context valueForKey:SDWebImageContextImageScaleFactor] doubleValue] : SDImageScaleForKey(self.cacheKey); + if (scale < 1) { + scale = 1; + } UIImage *image; if (!decodeFirstFrame) { // check whether we should use `SDAnimatedImage` if ([self.context valueForKey:SDWebImageContextAnimatedImageClass]) { Class animatedImageClass = [self.context valueForKey:SDWebImageContextAnimatedImageClass]; if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { - CGFloat scale = SDImageScaleForKey(self.cacheKey); image = [[animatedImageClass alloc] initWithData:imageData scale:scale]; if (self.options & SDWebImageDownloaderPreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { [((id)image) preloadAllFrames]; @@ -469,8 +474,7 @@ didReceiveResponse:(NSURLResponse *)response } } if (!image) { - image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame)}]; - image = [self scaledImageForKey:self.cacheKey image:image]; + image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageContextImageScaleFactor : @(scale)}]; } BOOL shouldDecode = self.shouldDecompressImages; @@ -547,10 +551,6 @@ didReceiveResponse:(NSURLResponse *)response return _cacheKey; } -- (nullable UIImage *)scaledImageForKey:(nullable NSString *)key image:(nullable UIImage *)image { - return SDScaledImageForKey(key, image); -} - - (BOOL)shouldContinueWhenAppEntersBackground { return self.options & SDWebImageDownloaderContinueInBackground; } diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index 71d66d3f..175ce792 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -85,10 +85,12 @@ return nil; } size_t count = CGImageSourceGetCount(source); - CGFloat scale = 1.0; + CGFloat scale = 1; if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; - scale = MAX(1.0, scale); + if (scale < 1) { + scale = 1; + } } UIImage *animatedImage; diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index afb3387a..3de49c54 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -86,10 +86,12 @@ UIImage *image = [[UIImage alloc] initWithData:data]; return image; #else - CGFloat scale = 1.0; + CGFloat scale = 1; if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; - scale = MAX(1.0, scale); + if (scale < 1) { + scale = 1; + } } UIImage *image = [[UIImage alloc] initWithData:data scale:scale]; if (!image) { diff --git a/SDWebImage/SDWebImageWebPCoder.m b/SDWebImage/SDWebImageWebPCoder.m index bddf19d1..476df025 100644 --- a/SDWebImage/SDWebImageWebPCoder.m +++ b/SDWebImage/SDWebImageWebPCoder.m @@ -115,10 +115,12 @@ dispatch_semaphore_signal(self->_lock); BOOL hasAnimation = flags & ANIMATION_FLAG; BOOL decodeFirstFrame = [[options valueForKey:SDWebImageCoderDecodeFirstFrameOnly] boolValue]; #if SD_UIKIT || SD_WATCH - CGFloat scale = 1.0; + CGFloat scale = 1; if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; - scale = MAX(1.0, scale); + if (scale < 1) { + scale = 1; + } } #endif if (!hasAnimation) { From 1a3fb834a03dce188bcd8b2b0fbc3c4b7cda0e6e Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 8 Apr 2018 00:06:11 +0800 Subject: [PATCH 101/361] Add SDScaledImageForScaleFactor, make the API more clear. Fix the scale factor option issue --- SDWebImage/SDImageCache.m | 5 +- SDWebImage/SDWebImageCodersManager.m | 19 +++++- SDWebImage/SDWebImageDefine.h | 21 ++++-- SDWebImage/SDWebImageDefine.m | 78 ++++++++++++---------- SDWebImage/SDWebImageDownloaderOperation.m | 10 +-- SDWebImage/UIImage+WebCache.h | 2 +- 6 files changed, 88 insertions(+), 47 deletions(-) diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 7505da15..180352e4 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -485,7 +485,8 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (data) { UIImage *image; BOOL decodeFirstFrame = options & SDImageCacheDecodeFirstFrameOnly; - CGFloat scale = [context valueForKey:SDWebImageContextImageScaleFactor] ? [[context valueForKey:SDWebImageContextImageScaleFactor] doubleValue] : SDImageScaleForKey(key); + NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor]; + CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(key); if (!decodeFirstFrame) { // check whether we should use `SDAnimatedImage` if ([context valueForKey:SDWebImageContextAnimatedImageClass]) { @@ -499,7 +500,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } } if (!image) { - image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageContextImageScaleFactor : @(scale)}]; + image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; } BOOL shouldDecode = YES; if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { diff --git a/SDWebImage/SDWebImageCodersManager.m b/SDWebImage/SDWebImageCodersManager.m index 7c755533..737b5247 100644 --- a/SDWebImage/SDWebImageCodersManager.m +++ b/SDWebImage/SDWebImageCodersManager.m @@ -15,6 +15,7 @@ #endif #import "NSImage+Additions.h" #import "UIImage+WebCache.h" +#import "SDWebImageDefine.h" @interface SDWebImageCodersManager () @@ -100,6 +101,13 @@ return nil; } BOOL decodeFirstFrame = [[options valueForKey:SDWebImageCoderDecodeFirstFrameOnly] boolValue]; + CGFloat scale = 1; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if (scale < 1) { + scale = 1; + } + } UIImage *image; for (id coder in self.coders) { if ([coder canDecodeFromData:data]) { @@ -107,8 +115,15 @@ break; } } - if (decodeFirstFrame && image.images.count > 0) { - image = image.images.firstObject; + if (image) { + // Check static image + if (decodeFirstFrame && image.images.count > 0) { + image = image.images.firstObject; + } + // Check image scale + if (scale > 1 && scale != image.scale) { + image = SDScaledImageForScaleFactor(scale, image); + } } return image; diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index a6e70b1f..c8de8213 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -16,16 +16,19 @@ typedef NSMutableDictionary SDWebImageMutableContex #pragma mark - Image scale /** - Return the image scale from the specify key, supports file name and url key + Return the image scale factor for the specify key, supports file name and url key. + This is the built-in way to check the scale factor when we have no context about it. Because scale factor is not stored in image data (It's typically from filename). + However, you can also provide custom scale factor as well, see `SDWebImageContextImageScaleFactor`. @param key The image cache key @return The scale factor for image */ -FOUNDATION_EXPORT CGFloat SDImageScaleForKey(NSString * _Nullable key); +FOUNDATION_EXPORT CGFloat SDImageScaleFactorForKey(NSString * _Nullable key); /** - Scale the image with the scale factor from the specify key. If no need to scale, return the original image - This only works for `UIImage`(UIKit) or `NSImage`(AppKit). + Scale the image with the scale factor for the specify key. If no need to scale, return the original image. + This works for `UIImage`(UIKit) or `NSImage`(AppKit). And this function also preserve the associated value in `UIImage+WebCache`. + @note This is actually a convenience function, which firstlly call `SDImageScaleFactorForKey` and then call `SDScaledImageForScaleFactor`, kept for backward compatibility. @param key The image cache key @param image The image @@ -33,6 +36,16 @@ FOUNDATION_EXPORT CGFloat SDImageScaleForKey(NSString * _Nullable key); */ FOUNDATION_EXPORT UIImage * _Nullable SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image); +/** + Scale the image with the scale factor. If no need to scale, return the original image. + This works for `UIImage`(UIKit) or `NSImage`(AppKit). And this function also preserve the associated value in `UIImage+WebCache`. + + @param scale The image scale factor + @param image The image + @return The scaled image + */ +FOUNDATION_EXPORT UIImage * _Nullable SDScaledImageForScaleFactor(CGFloat scale, UIImage * _Nullable image); + #pragma mark - WebCache Options typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m index 41da36e4..413eec6d 100644 --- a/SDWebImage/SDWebImageDefine.m +++ b/SDWebImage/SDWebImageDefine.m @@ -16,7 +16,7 @@ static inline NSArray * _Nonnull SDImageScaleFactors() { return @[@2, @3]; } -inline CGFloat SDImageScaleForKey(NSString * _Nullable key) { +inline CGFloat SDImageScaleFactorForKey(NSString * _Nullable key) { CGFloat scale = 1; if (!key) { return scale; @@ -55,46 +55,56 @@ inline CGFloat SDImageScaleForKey(NSString * _Nullable key) { return scale; } -inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) { +inline UIImage * _Nullable SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) { if (!image) { return nil; } - - CGFloat scale = SDImageScaleForKey(key); - if (scale > 1) { - UIImage *scaledImage; - if (image.sd_isAnimated) { - UIImage *animatedImage; + CGFloat scale = SDImageScaleFactorForKey(key); + return SDScaledImageForScaleFactor(scale, image); +} + +inline UIImage * _Nullable SDScaledImageForScaleFactor(CGFloat scale, UIImage * _Nullable image) { + if (!image) { + return nil; + } + if (scale <= 1) { + return image; + } + if (scale == image.scale) { + return image; + } + UIImage *scaledImage; + if (image.sd_isAnimated) { + UIImage *animatedImage; #if SD_UIKIT || SD_WATCH - // `UIAnimatedImage` images share the same size and scale. - NSMutableArray *scaledImages = [NSMutableArray array]; - - for (UIImage *tempImage in image.images) { - UIImage *tempScaledImage = [[UIImage alloc] initWithCGImage:tempImage.CGImage scale:scale orientation:tempImage.imageOrientation]; - [scaledImages addObject:tempScaledImage]; - } - - animatedImage = [UIImage animatedImageWithImages:scaledImages duration:image.duration]; - animatedImage.sd_imageLoopCount = image.sd_imageLoopCount; -#else - // Animated GIF for `NSImage` need to grab `NSBitmapImageRep` - NSSize size = NSMakeSize(image.size.width / scale, image.size.height / scale); - animatedImage = [[NSImage alloc] initWithSize:size]; - NSBitmapImageRep *bitmapImageRep = image.bitmapImageRep; - [animatedImage addRepresentation:bitmapImageRep]; -#endif - scaledImage = animatedImage; - } else { -#if SD_UIKIT || SD_WATCH - scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; -#else - scaledImage = [[NSImage alloc] initWithCGImage:image.CGImage size:NSZeroSize]; -#endif + // `UIAnimatedImage` images share the same size and scale. + NSMutableArray *scaledImages = [NSMutableArray array]; + + for (UIImage *tempImage in image.images) { + UIImage *tempScaledImage = [[UIImage alloc] initWithCGImage:tempImage.CGImage scale:scale orientation:tempImage.imageOrientation]; + [scaledImages addObject:tempScaledImage]; } - return scaledImage; + animatedImage = [UIImage animatedImageWithImages:scaledImages duration:image.duration]; + animatedImage.sd_imageLoopCount = image.sd_imageLoopCount; +#else + // Animated GIF for `NSImage` need to grab `NSBitmapImageRep` + NSSize size = NSMakeSize(image.size.width / scale, image.size.height / scale); + animatedImage = [[NSImage alloc] initWithSize:size]; + NSBitmapImageRep *bitmapImageRep = image.bitmapImageRep; + [animatedImage addRepresentation:bitmapImageRep]; +#endif + scaledImage = animatedImage; + } else { +#if SD_UIKIT || SD_WATCH + scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; +#else + scaledImage = [[NSImage alloc] initWithCGImage:image.CGImage size:NSZeroSize]; +#endif } - return image; + scaledImage.sd_isIncremental = image.sd_isIncremental; + + return scaledImage; } #pragma mark - Context option diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 87dc7e3e..7dd973b4 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -364,7 +364,8 @@ didReceiveResponse:(NSURLResponse *)response // check whether we should use `SDAnimatedImage` UIImage *image; BOOL decodeFirstFrame = self.options & SDWebImageDownloaderDecodeFirstFrameOnly; - CGFloat scale = [self.context valueForKey:SDWebImageContextImageScaleFactor] ? [[self.context valueForKey:SDWebImageContextImageScaleFactor] doubleValue] : SDImageScaleForKey(self.cacheKey); + NSNumber *scaleValue = [self.context valueForKey:SDWebImageContextImageScaleFactor]; + CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(self.cacheKey); if (!decodeFirstFrame) { // check whether we should use `SDAnimatedImage` if ([self.context valueForKey:SDWebImageContextAnimatedImageClass]) { @@ -375,7 +376,7 @@ didReceiveResponse:(NSURLResponse *)response } } if (!image) { - image = [self.progressiveCoder incrementalDecodedImageWithOptions:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageContextImageScaleFactor : @(scale)}]; + image = [self.progressiveCoder incrementalDecodedImageWithOptions:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; } if (image) { BOOL shouldDecode = self.shouldDecompressImages; @@ -456,7 +457,8 @@ didReceiveResponse:(NSURLResponse *)response // decode the image in coder queue dispatch_async(self.coderQueue, ^{ BOOL decodeFirstFrame = self.options & SDWebImageDownloaderDecodeFirstFrameOnly; - CGFloat scale = [self.context valueForKey:SDWebImageContextImageScaleFactor] ? [[self.context valueForKey:SDWebImageContextImageScaleFactor] doubleValue] : SDImageScaleForKey(self.cacheKey); + NSNumber *scaleValue = [self.context valueForKey:SDWebImageContextImageScaleFactor]; + CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(self.cacheKey); if (scale < 1) { scale = 1; } @@ -474,7 +476,7 @@ didReceiveResponse:(NSURLResponse *)response } } if (!image) { - image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageContextImageScaleFactor : @(scale)}]; + image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; } BOOL shouldDecode = self.shouldDecompressImages; diff --git a/SDWebImage/UIImage+WebCache.h b/SDWebImage/UIImage+WebCache.h index 0c7bf351..b7991976 100644 --- a/SDWebImage/UIImage+WebCache.h +++ b/SDWebImage/UIImage+WebCache.h @@ -25,7 +25,7 @@ * UIKit: * Check the `images` array property * AppKit: - * NSImage currently only support animated via GIF imageRep unlike UIImage. It will check all the imageRef + * NSImage currently only support animated via GIF imageRep unlike UIImage. It will check the imageRep's frame count. */ @property (nonatomic, assign, readonly) BOOL sd_isAnimated; From cbf85816968e76256d5fde62d3c07461131d1068 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 8 Apr 2018 14:53:14 +0800 Subject: [PATCH 102/361] Fix the scale factor issue on macOS using helper methods to match the behavior of UIKit. Also remove the unused API on NSImage category --- SDWebImage/NSImage+Additions.h | 40 +++++++++++++++-- SDWebImage/NSImage+Additions.m | 66 +++++++++++++++++++++++----- SDWebImage/SDAnimatedImage.m | 5 ++- SDWebImage/SDWebImageAPNGCoder.m | 31 ++++++++----- SDWebImage/SDWebImageCoderHelper.m | 32 ++++++++------ SDWebImage/SDWebImageCodersManager.m | 18 -------- SDWebImage/SDWebImageDefine.m | 19 +++++--- SDWebImage/SDWebImageGIFCoder.m | 31 ++++++++----- SDWebImage/SDWebImageImageIOCoder.m | 20 ++++++--- SDWebImage/SDWebImageManager.m | 2 +- SDWebImage/SDWebImageWebPCoder.m | 23 ++++++---- SDWebImage/UIImage+Transform.m | 33 +++++++++++--- SDWebImage/UIImage+WebCache.m | 21 +++++++-- Tests/Tests/SDWebImageDecoderTests.m | 2 + 14 files changed, 242 insertions(+), 101 deletions(-) diff --git a/SDWebImage/NSImage+Additions.h b/SDWebImage/NSImage+Additions.h index a5264ed8..08aad12b 100644 --- a/SDWebImage/NSImage+Additions.h +++ b/SDWebImage/NSImage+Additions.h @@ -8,16 +8,50 @@ #import "SDWebImageCompat.h" -// This category is provided to easily write cross-platform code. For common usage, see `UIImage+WebCache`. +// This category is provided to easily write cross-platform(AppKit/UIKit) code. For common usage, see `UIImage+WebCache`. #if SD_MAC @interface NSImage (Additions) +/** +The underlying Core Graphics image object. This will actually `CGImageForProposedRect` with the image size. + */ @property (nonatomic, readonly, nullable) CGImageRef CGImage; -@property (nonatomic, readonly, nullable) NSArray *images; +/** + The scale factor of the image. This wil actually use image size, and its `CGImage`'s pixel size to calculate the scale factor. Should be greater than or equal to 1.0. + */ @property (nonatomic, readonly) CGFloat scale; -@property (nonatomic, readonly, nullable) NSBitmapImageRep *bitmapImageRep; + +// These are convenience methods to make AppKit's `NSImage` match UIKit's `UIImage` behavior. The scale factor should be greater than or equal to 1.0. + +/** + Returns an image object with the scale factor. The representation is created from the Core Graphics image object. + @note The difference between this and `initWithCGImage:size` is that `initWithCGImage:size` will create a `NSCGImageSnapshotRep` but not `NSBitmapImageRep` instance. And it will always `backingScaleFactor` as scale factor. + + @param cgImage A Core Graphics image object + @param scale The image scale factor + @return The image object + */ +- (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale; + +/** + Returns an image object with the scale factor. The representation is created from the image data. + @note The difference between these this and `initWithData:` is that `initWithData:` will always `backingScaleFactor` as scale factor. + + @param data The image data + @param scale The image scale factor + @return The image object + */ +- (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale; + +@end + +@interface NSBitmapImageRep (Additions) + +// These method's function is the same as `NSImage`'s function. For `NSBitmapImageRep`. +- (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale; +- (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale; @end diff --git a/SDWebImage/NSImage+Additions.m b/SDWebImage/NSImage+Additions.m index 65a66621..984aa0fd 100644 --- a/SDWebImage/NSImage+Additions.m +++ b/SDWebImage/NSImage+Additions.m @@ -18,28 +18,72 @@ return cgImage; } -- (NSArray *)images { - return nil; -} - - (CGFloat)scale { CGFloat scale = 1; CGFloat width = self.size.width; if (width > 0) { - // Use CGImage to get pixel width, NSImageRep.pixelsWide always double on Retina screen + // Use CGImage to get pixel width, NSImageRep.pixelsWide may be double on Retina screen NSUInteger pixelWidth = CGImageGetWidth(self.CGImage); scale = pixelWidth / width; } return scale; } -- (NSBitmapImageRep *)bitmapImageRep { - NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); - NSImageRep *imageRep = [self bestRepresentationForRect:imageRect context:nil hints:nil]; - if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) { - return (NSBitmapImageRep *)imageRep; +- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale { + if (scale < 1) { + scale = 1; } - return nil; + NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage scale:scale]; + NSSize size = NSMakeSize(imageRep.pixelsWide / scale, imageRep.pixelsHigh / scale); + self = [self initWithSize:size]; + if (self) { + [self addRepresentation:imageRep]; + } + return self; +} + +- (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale { + if (scale < 1) { + scale = 1; + } + NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithData:data scale:scale]; + if (!imageRep) { + return nil; + } + NSSize size = NSMakeSize(imageRep.pixelsWide / scale, imageRep.pixelsHigh / scale); + self = [self initWithSize:size]; + if (self) { + [self addRepresentation:imageRep]; + } + return self; +} + +@end + +@implementation NSBitmapImageRep (Additions) + +- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale { + self = [self initWithCGImage:cgImage]; + if (self) { + if (scale < 1) { + scale = 1; + } + NSSize size = NSMakeSize(self.pixelsWide / scale, self.pixelsHigh / scale); + self.size = size; + } + return self; +} + +- (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale { + self = [self initWithData:data]; + if (self) { + if (scale < 1) { + scale = 1; + } + NSSize size = NSMakeSize(self.pixelsWide / scale, self.pixelsHigh / scale); + self.size = size; + } + return self; } @end diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index a6d4b8bf..3dccbdeb 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -310,7 +310,7 @@ static NSArray *SDBundlePreferredScales() { return nil; } #if SD_MAC - self = [super initWithCGImage:image.CGImage size:NSZeroSize]; + self = [super initWithCGImage:image.CGImage scale:scale]; #else self = [super initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; #endif @@ -353,7 +353,10 @@ static NSArray *SDBundlePreferredScales() { NSNumber *scale = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(scale))]; NSData *animatedImageData = [aDecoder decodeObjectOfClass:[NSData class] forKey:NSStringFromSelector(@selector(animatedImageData))]; if (animatedImageData) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-designated-initializers" return [self initWithData:animatedImageData scale:scale.doubleValue]; +#pragma clang diagnostic pop } else { return [super initWithCoder:aDecoder]; } diff --git a/SDWebImage/SDWebImageAPNGCoder.m b/SDWebImage/SDWebImageAPNGCoder.m index be729350..0fea08c6 100644 --- a/SDWebImage/SDWebImageAPNGCoder.m +++ b/SDWebImage/SDWebImageAPNGCoder.m @@ -82,10 +82,19 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef if (!data) { return nil; } + CGFloat scale = 1; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if (scale < 1) { + scale = 1; + } + } #if SD_MAC SDAnimatedImageRep *imageRep = [[SDAnimatedImageRep alloc] initWithData:data]; - NSImage *animatedImage = [[NSImage alloc] initWithSize:imageRep.size]; + NSSize size = NSMakeSize(imageRep.pixelsWide / scale, imageRep.pixelsHigh / scale); + imageRep.size = size; + NSImage *animatedImage = [[NSImage alloc] initWithSize:size]; [animatedImage addRepresentation:imageRep]; return animatedImage; #else @@ -95,13 +104,6 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef return nil; } size_t count = CGImageSourceGetCount(source); - CGFloat scale = 1; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; - if (scale < 1) { - scale = 1; - } - } UIImage *animatedImage; if (count <= 1) { @@ -277,10 +279,17 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL); if (partialImageRef) { + CGFloat scale = 1; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if (scale < 1) { + scale = 1; + } + } #if SD_UIKIT || SD_WATCH - image = [[UIImage alloc] initWithCGImage:partialImageRef]; + image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:UIImageOrientationUp]; #elif SD_MAC - image = [[UIImage alloc] initWithCGImage:partialImageRef size:NSZeroSize]; + image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale]; #endif CGImageRelease(partialImageRef); } @@ -375,7 +384,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef CGImageRelease(imageRef); } #if SD_MAC - UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef size:NSZeroSize]; + UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:1]; #else UIImage *image = [UIImage imageWithCGImage:newImageRef]; #endif diff --git a/SDWebImage/SDWebImageCoderHelper.m b/SDWebImage/SDWebImageCoderHelper.m index 29f6b739..472d1ee6 100644 --- a/SDWebImage/SDWebImageCoderHelper.m +++ b/SDWebImage/SDWebImageCoderHelper.m @@ -103,8 +103,14 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over return nil; } CFRelease(imageDestination); + CGFloat scale = frames.firstObject.image.scale; + if (scale < 1) { + scale = 1; + } SDAnimatedImageRep *imageRep = [[SDAnimatedImageRep alloc] initWithData:imageData]; - animatedImage = [[NSImage alloc] initWithSize:imageRep.size]; + NSSize size = NSMakeSize(imageRep.pixelsWide / scale, imageRep.pixelsHigh / scale); + imageRep.size = size; + animatedImage = [[NSImage alloc] initWithSize:size]; [animatedImage addRepresentation:imageRep]; #endif @@ -157,27 +163,27 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over #else - NSBitmapImageRep *bitmapRep; - for (NSImageRep *imageRep in animatedImage.representations) { - if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) { - bitmapRep = (NSBitmapImageRep *)imageRep; - break; - } + NSRect imageRect = NSMakeRect(0, 0, animatedImage.size.width, animatedImage.size.height); + NSImageRep *imageRep = [animatedImage bestRepresentationForRect:imageRect context:nil hints:nil]; + NSBitmapImageRep *bitmapImageRep; + if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) { + bitmapImageRep = (NSBitmapImageRep *)imageRep; } - if (bitmapRep) { - frameCount = [[bitmapRep valueForProperty:NSImageFrameCount] unsignedIntegerValue]; + if (!bitmapImageRep) { + return nil; } - + frameCount = [[bitmapImageRep valueForProperty:NSImageFrameCount] unsignedIntegerValue]; if (frameCount == 0) { return nil; } + CGFloat scale = animatedImage.scale; for (size_t i = 0; i < frameCount; i++) { @autoreleasepool { // NSBitmapImageRep need to manually change frame. "Good taste" API - [bitmapRep setProperty:NSImageCurrentFrame withValue:@(i)]; - float frameDuration = [[bitmapRep valueForProperty:NSImageCurrentFrameDuration] floatValue]; - NSImage *frameImage = [[NSImage alloc] initWithCGImage:bitmapRep.CGImage size:NSZeroSize]; + [bitmapImageRep setProperty:NSImageCurrentFrame withValue:@(i)]; + float frameDuration = [[bitmapImageRep valueForProperty:NSImageCurrentFrameDuration] floatValue]; + NSImage *frameImage = [[NSImage alloc] initWithCGImage:bitmapImageRep.CGImage scale:scale]; SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:frameImage duration:frameDuration]; [frames addObject:frame]; } diff --git a/SDWebImage/SDWebImageCodersManager.m b/SDWebImage/SDWebImageCodersManager.m index 737b5247..67e2e2c8 100644 --- a/SDWebImage/SDWebImageCodersManager.m +++ b/SDWebImage/SDWebImageCodersManager.m @@ -100,14 +100,6 @@ if (!data) { return nil; } - BOOL decodeFirstFrame = [[options valueForKey:SDWebImageCoderDecodeFirstFrameOnly] boolValue]; - CGFloat scale = 1; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; - if (scale < 1) { - scale = 1; - } - } UIImage *image; for (id coder in self.coders) { if ([coder canDecodeFromData:data]) { @@ -115,16 +107,6 @@ break; } } - if (image) { - // Check static image - if (decodeFirstFrame && image.images.count > 0) { - image = image.images.firstObject; - } - // Check image scale - if (scale > 1 && scale != image.scale) { - image = SDScaledImageForScaleFactor(scale, image); - } - } return image; } diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m index 413eec6d..35b518e4 100644 --- a/SDWebImage/SDWebImageDefine.m +++ b/SDWebImage/SDWebImageDefine.m @@ -88,18 +88,25 @@ inline UIImage * _Nullable SDScaledImageForScaleFactor(CGFloat scale, UIImage * animatedImage = [UIImage animatedImageWithImages:scaledImages duration:image.duration]; animatedImage.sd_imageLoopCount = image.sd_imageLoopCount; #else - // Animated GIF for `NSImage` need to grab `NSBitmapImageRep` - NSSize size = NSMakeSize(image.size.width / scale, image.size.height / scale); - animatedImage = [[NSImage alloc] initWithSize:size]; - NSBitmapImageRep *bitmapImageRep = image.bitmapImageRep; - [animatedImage addRepresentation:bitmapImageRep]; + // Animated GIF for `NSImage` need to grab `NSBitmapImageRep`; + NSRect imageRect = NSMakeRect(0, 0, image.size.width, image.size.height); + NSImageRep *imageRep = [image bestRepresentationForRect:imageRect context:nil hints:nil]; + NSBitmapImageRep *bitmapImageRep; + if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) { + bitmapImageRep = (NSBitmapImageRep *)imageRep; + } + if (bitmapImageRep) { + NSSize size = NSMakeSize(image.size.width / scale, image.size.height / scale); + animatedImage = [[NSImage alloc] initWithSize:size]; + [animatedImage addRepresentation:bitmapImageRep]; + } #endif scaledImage = animatedImage; } else { #if SD_UIKIT || SD_WATCH scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; #else - scaledImage = [[NSImage alloc] initWithCGImage:image.CGImage size:NSZeroSize]; + scaledImage = [[NSImage alloc] initWithCGImage:image.CGImage scale:scale]; #endif } scaledImage.sd_isIncremental = image.sd_isIncremental; diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index 175ce792..43e646a3 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -72,10 +72,19 @@ if (!data) { return nil; } + CGFloat scale = 1; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if (scale < 1) { + scale = 1; + } + } #if SD_MAC SDAnimatedImageRep *imageRep = [[SDAnimatedImageRep alloc] initWithData:data]; - NSImage *animatedImage = [[NSImage alloc] initWithSize:imageRep.size]; + NSSize size = NSMakeSize(imageRep.pixelsWide / scale, imageRep.pixelsHigh / scale); + imageRep.size = size; + NSImage *animatedImage = [[NSImage alloc] initWithSize:size]; [animatedImage addRepresentation:imageRep]; return animatedImage; #else @@ -85,13 +94,6 @@ return nil; } size_t count = CGImageSourceGetCount(source); - CGFloat scale = 1; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; - if (scale < 1) { - scale = 1; - } - } UIImage *animatedImage; BOOL decodeFirstFrame = [options[SDWebImageCoderDecodeFirstFrameOnly] boolValue]; @@ -224,10 +226,17 @@ CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL); if (partialImageRef) { + CGFloat scale = 1; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if (scale < 1) { + scale = 1; + } + } #if SD_UIKIT || SD_WATCH - image = [[UIImage alloc] initWithCGImage:partialImageRef]; + image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:UIImageOrientationUp]; #elif SD_MAC - image = [[UIImage alloc] initWithCGImage:partialImageRef size:NSZeroSize]; + image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale]; #endif CGImageRelease(partialImageRef); } @@ -375,7 +384,7 @@ CGImageRelease(imageRef); } #if SD_MAC - UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef size:NSZeroSize]; + UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:1]; #else UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef]; #endif diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index 3de49c54..47e622df 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -81,11 +81,6 @@ if (!data) { return nil; } - -#if SD_MAC - UIImage *image = [[UIImage alloc] initWithData:data]; - return image; -#else CGFloat scale = 1; if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; @@ -93,7 +88,11 @@ scale = 1; } } + UIImage *image = [[UIImage alloc] initWithData:data scale:scale]; +#if SD_MAC + return image; +#else if (!image) { return nil; } @@ -182,10 +181,17 @@ #endif if (partialImageRef) { + CGFloat scale = 1; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if (scale < 1) { + scale = 1; + } + } #if SD_UIKIT || SD_WATCH - image = [[UIImage alloc] initWithCGImage:partialImageRef scale:1 orientation:_orientation]; + image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:_orientation]; #elif SD_MAC - image = [[UIImage alloc] initWithCGImage:partialImageRef size:NSZeroSize]; + image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale]; #endif CGImageRelease(partialImageRef); } diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 1fa92d5e..cce41d86 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -261,7 +261,7 @@ if (options & SDWebImageRefreshCached && cachedImage && !downloadedImage) { // Image refresh hit the NSURLCache cache, do not call the completion block - } else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && transformer) { + } else if (downloadedImage && (!downloadedImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage)) && transformer) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ UIImage *transformedImage = [transformer transformedImageWithImage:downloadedImage forKey:key]; if (transformedImage && finished) { diff --git a/SDWebImage/SDWebImageWebPCoder.m b/SDWebImage/SDWebImageWebPCoder.m index 476df025..2c91178d 100644 --- a/SDWebImage/SDWebImageWebPCoder.m +++ b/SDWebImage/SDWebImageWebPCoder.m @@ -114,7 +114,6 @@ dispatch_semaphore_signal(self->_lock); uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS); BOOL hasAnimation = flags & ANIMATION_FLAG; BOOL decodeFirstFrame = [[options valueForKey:SDWebImageCoderDecodeFirstFrameOnly] boolValue]; -#if SD_UIKIT || SD_WATCH CGFloat scale = 1; if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; @@ -122,7 +121,6 @@ dispatch_semaphore_signal(self->_lock); scale = 1; } } -#endif if (!hasAnimation) { // for static single webp image CGImageRef imageRef = [self sd_createWebpImageWithData:webpData]; @@ -132,7 +130,7 @@ dispatch_semaphore_signal(self->_lock); #if SD_UIKIT || SD_WATCH UIImage *staticImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; #else - UIImage *staticImage = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; + UIImage *staticImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale]; #endif CGImageRelease(imageRef); WebPDemuxDelete(demuxer); @@ -154,7 +152,7 @@ dispatch_semaphore_signal(self->_lock); #if SD_UIKIT || SD_WATCH UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; #else - UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; + UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale]; #endif CGImageRelease(imageRef); WebPDemuxReleaseIterator(&iter); @@ -185,7 +183,7 @@ dispatch_semaphore_signal(self->_lock); #if SD_UIKIT || SD_WATCH UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; #else - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale]; #endif CGImageRelease(imageRef); @@ -279,11 +277,18 @@ dispatch_semaphore_signal(self->_lock); CGContextRelease(canvas); return nil; } + CGFloat scale = 1; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if (scale < 1) { + scale = 1; + } + } #if SD_UIKIT || SD_WATCH - image = [[UIImage alloc] initWithCGImage:newImageRef]; + image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale orientation:UIImageOrientationUp]; #else - image = [[UIImage alloc] initWithCGImage:newImageRef size:NSZeroSize]; + image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale]; #endif CGImageRelease(newImageRef); CGContextRelease(canvas); @@ -664,7 +669,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { #if SD_UIKIT || SD_WATCH image = [[UIImage alloc] initWithCGImage:imageRef]; #else - image = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; + image = [[UIImage alloc] initWithCGImage:imageRef scale:1]; #endif CGImageRelease(imageRef); } else { @@ -694,7 +699,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { #if SD_UIKIT || SD_WATCH image = [[UIImage alloc] initWithCGImage:imageRef]; #else - image = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; + image = [[UIImage alloc] initWithCGImage:imageRef scale:1]; #endif CGImageRelease(imageRef); } diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 81dc1728..847a2682 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -24,6 +24,15 @@ static CGContextRef SDCGContextCreateARGBBitmapContext(CGSize size, BOOL opaque, CGImageAlphaInfo alphaInfo = (opaque ? kCGImageAlphaNoneSkipFirst : kCGImageAlphaPremultipliedFirst); CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, space, kCGBitmapByteOrderDefault | alphaInfo); CGColorSpaceRelease(space); + if (!context) { + return NULL; + } + if (scale == 0) { + // Match `UIGraphicsBeginImageContextWithOptions`, reset to the scale factor of the device’s main screen if scale is 0. + scale = [NSScreen mainScreen].backingScaleFactor; + } + CGContextScaleCTM(context, scale, scale); + return context; } #endif @@ -71,7 +80,17 @@ static UIImage * SDGraphicsGetImageFromCurrentImageContext(void) { if (!imageRef) { return nil; } - NSImage *image = [[NSImage alloc] initWithCGImage:imageRef size:NSZeroSize]; + CGAffineTransform transform = CGContextGetCTM(context); + CGFloat xs = transform.a; + CGFloat ys = transform.d; + CGFloat scale; + if (xs == ys && xs > 0) { + scale = xs; + } else { + // Protect if x/y axis scale factor not equal + scale = [NSScreen mainScreen].backingScaleFactor; + } + NSImage *image = [[NSImage alloc] initWithCGImage:imageRef scale:scale]; CGImageRelease(imageRef); return image; #endif @@ -303,7 +322,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation]; #else - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale]; #endif CGImageRelease(imageRef); return image; @@ -381,7 +400,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH UIImage *img = [UIImage imageWithCGImage:imgRef scale:self.scale orientation:self.imageOrientation]; #else - UIImage *img = [[UIImage alloc] initWithCGImage:imgRef size:NSZeroSize]; + UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale]; #endif CGImageRelease(imgRef); CGContextRelease(context); @@ -417,7 +436,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH UIImage *img = [UIImage imageWithCGImage:imgRef scale:self.scale orientation:self.imageOrientation]; #else - UIImage *img = [[UIImage alloc] initWithCGImage:imgRef size:NSZeroSize]; + UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale]; #endif CGImageRelease(imgRef); return img; @@ -434,7 +453,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH return [UIImage imageWithCGImage:self.CGImage scale:self.scale orientation:self.imageOrientation]; #else - return [[UIImage alloc] initWithCGImage:self.CGImage size:NSZeroSize]; + return [[UIImage alloc] initWithCGImage:self.CGImage scale:self.scale]; #endif } @@ -651,7 +670,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH UIImage *outputImage = [UIImage imageWithCGImage:effectCGImage scale:self.scale orientation:self.imageOrientation]; #else - UIImage *outputImage = [[UIImage alloc] initWithCGImage:effectCGImage size:NSZeroSize]; + UIImage *outputImage = [[UIImage alloc] initWithCGImage:effectCGImage scale:self.scale]; #endif CGImageRelease(effectCGImage); @@ -676,7 +695,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation]; #else - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize]; + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale]; #endif CGImageRelease(imageRef); diff --git a/SDWebImage/UIImage+WebCache.m b/SDWebImage/UIImage+WebCache.m index c7a82779..ffdfe35f 100644 --- a/SDWebImage/UIImage+WebCache.m +++ b/SDWebImage/UIImage+WebCache.m @@ -51,7 +51,12 @@ - (NSUInteger)sd_imageLoopCount { NSUInteger imageLoopCount = 0; - NSBitmapImageRep *bitmapImageRep = self.bitmapImageRep; + NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); + NSImageRep *imageRep = [self bestRepresentationForRect:imageRect context:nil hints:nil]; + NSBitmapImageRep *bitmapImageRep; + if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) { + bitmapImageRep = (NSBitmapImageRep *)imageRep; + } if (bitmapImageRep) { imageLoopCount = [[bitmapImageRep valueForProperty:NSImageLoopCount] unsignedIntegerValue]; } @@ -59,7 +64,12 @@ } - (void)setSd_imageLoopCount:(NSUInteger)sd_imageLoopCount { - NSBitmapImageRep *bitmapImageRep = self.bitmapImageRep; + NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); + NSImageRep *imageRep = [self bestRepresentationForRect:imageRect context:nil hints:nil]; + NSBitmapImageRep *bitmapImageRep; + if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) { + bitmapImageRep = (NSBitmapImageRep *)imageRep; + } if (bitmapImageRep) { [bitmapImageRep setProperty:NSImageLoopCount withValue:@(sd_imageLoopCount)]; } @@ -67,7 +77,12 @@ - (BOOL)sd_isAnimated { BOOL isGIF = NO; - NSBitmapImageRep *bitmapImageRep = self.bitmapImageRep; + NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); + NSImageRep *imageRep = [self bestRepresentationForRect:imageRect context:nil hints:nil]; + NSBitmapImageRep *bitmapImageRep; + if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) { + bitmapImageRep = (NSBitmapImageRep *)imageRep; + } if (bitmapImageRep) { NSUInteger frameCount = [[bitmapImageRep valueForProperty:NSImageFrameCount] unsignedIntegerValue]; isGIF = frameCount > 1 ? YES : NO; diff --git a/Tests/Tests/SDWebImageDecoderTests.m b/Tests/Tests/SDWebImageDecoderTests.m index 74c8605c..a3fd4cea 100644 --- a/Tests/Tests/SDWebImageDecoderTests.m +++ b/Tests/Tests/SDWebImageDecoderTests.m @@ -170,7 +170,9 @@ UIImage *outputImage = [coder decodedImageWithData:outputImageData options:nil]; expect(outputImage.size).to.equal(inputImage.size); expect(outputImage.scale).to.equal(inputImage.scale); +#if SD_UIKIT expect(outputImage.images.count).to.equal(inputImage.images.count); +#endif } @end From 22c293738ad00dac212f575e9b4c9861a48e1847 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 9 Apr 2018 13:42:52 +0800 Subject: [PATCH 103/361] Update the progressive coder/ animated coder init API, which pass the options to support extensibility --- SDWebImage/SDAnimatedImage.m | 2 +- SDWebImage/SDWebImageAPNGCoder.m | 37 ++++++++++++++++------ SDWebImage/SDWebImageCoder.h | 32 +++++++++++++++---- SDWebImage/SDWebImageCoder.m | 2 ++ SDWebImage/SDWebImageDownloaderOperation.m | 2 +- SDWebImage/SDWebImageGIFCoder.m | 21 +++++++++--- SDWebImage/SDWebImageImageIOCoder.m | 2 +- SDWebImage/SDWebImageWebPCoder.m | 25 +++++++++++---- Tests/Tests/SDAnimatedImageTest.m | 17 +++++++--- Tests/Tests/SDWebImageTestDecoder.m | 2 +- 10 files changed, 106 insertions(+), 36 deletions(-) diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index 3dccbdeb..6a715658 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -287,7 +287,7 @@ static NSArray *SDBundlePreferredScales() { for (idcoder in [SDWebImageCodersManager sharedManager].coders) { if ([coder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { if ([coder canDecodeFromData:data]) { - animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data]; + animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data options:@{SDWebImageCoderDecodeScaleFactor : @(scale)}]; break; } } diff --git a/SDWebImage/SDWebImageAPNGCoder.m b/SDWebImage/SDWebImageAPNGCoder.m index 0fea08c6..c3bb1e82 100644 --- a/SDWebImage/SDWebImageAPNGCoder.m +++ b/SDWebImage/SDWebImageAPNGCoder.m @@ -38,6 +38,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef #endif CGImageSourceRef _imageSource; NSData *_imageData; + CGFloat _scale; NSUInteger _loopCount; NSUInteger _frameCount; NSArray *_frames; @@ -106,7 +107,8 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef size_t count = CGImageSourceGetCount(source); UIImage *animatedImage; - if (count <= 1) { + BOOL decodeFirstFrame = [options[SDWebImageCoderDecodeFirstFrameOnly] boolValue]; + if (decodeFirstFrame || count <= 1) { animatedImage = [[UIImage alloc] initWithData:data scale:scale]; } else { NSMutableArray *frames = [NSMutableArray array]; @@ -198,14 +200,23 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef // Handle failure. return nil; } - if (frames.count == 0) { + NSMutableDictionary *properties = [NSMutableDictionary dictionary]; + double compressionQuality = 1; + if ([options valueForKey:SDWebImageCoderEncodeCompressionQuality]) { + compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue]; + } + [properties setValue:@(compressionQuality) forKey:(__bridge_transfer NSString *)kCGImageDestinationLossyCompressionQuality]; + + BOOL encodeFirstFrame = [options[SDWebImageCoderEncodeFirstFrameOnly] boolValue]; + if (encodeFirstFrame || frames.count == 0) { // for static single PNG images - CGImageDestinationAddImage(imageDestination, image.CGImage, nil); + CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); } else { // for animated APNG images NSUInteger loopCount = image.sd_imageLoopCount; - NSDictionary *pngProperties = @{(__bridge_transfer NSString *)kCGImagePropertyPNGDictionary: @{(__bridge_transfer NSString *)kCGImagePropertyAPNGLoopCount : @(loopCount)}}; - CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)pngProperties); + NSDictionary *pngProperties = @{(__bridge_transfer NSString *)kCGImagePropertyAPNGLoopCount : @(loopCount)}; + [properties setValue:pngProperties forKey:(__bridge_transfer NSString *)kCGImagePropertyPNGDictionary]; + CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)properties); for (size_t i = 0; i < frames.count; i++) { SDWebImageFrame *frame = frames[i]; @@ -232,7 +243,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef return ([NSData sd_imageFormatForImageData:data] == SDImageFormatPNG); } -- (instancetype)initIncremental { +- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options { self = [super init]; if (self) { _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)}); @@ -299,7 +310,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef } #pragma mark - SDWebImageAnimatedCoder -- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data { +- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data options:(nullable SDWebImageCoderOptions *)options { if (!data) { return nil; } @@ -315,6 +326,14 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef CFRelease(imageSource); return nil; } + CGFloat scale = 1; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if (scale < 1) { + scale = 1; + } + } + _scale = scale; _imageSource = imageSource; _imageData = data; #if SD_UIKIT @@ -384,9 +403,9 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef CGImageRelease(imageRef); } #if SD_MAC - UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:1]; + UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale]; #else - UIImage *image = [UIImage imageWithCGImage:newImageRef]; + UIImage *image = [UIImage imageWithCGImage:newImageRef scale:_scale orientation:UIImageOrientationUp]; #endif CGImageRelease(newImageRef); return image; diff --git a/SDWebImage/SDWebImageCoder.h b/SDWebImage/SDWebImageCoder.h index 22fbe61e..de73401c 100644 --- a/SDWebImage/SDWebImageCoder.h +++ b/SDWebImage/SDWebImageCoder.h @@ -13,19 +13,32 @@ typedef NSString * SDWebImageCoderOption NS_STRING_ENUM; typedef NSDictionary SDWebImageCoderOptions; +#pragma mark - Coder Options +// These options are for image decoding /** - A Boolean value indicating whether to decode the first frame only for animated image during decoding. (NSNumber) + A Boolean value indicating whether to decode the first frame only for animated image during decoding. (NSNumber). If not provide, decode animated image if need. + @note works for `SDWebImageCoder`. */ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderDecodeFirstFrameOnly; /** A CGFloat value which is greater than or equal to 1.0. This value specify the image scale factor for decoding. If not provide, use 1.0. (NSNumber) + @note works for `SDWebImageCoder`, `SDWebImageProgressiveCoder`, `SDWebImageAnimatedCoder`. */ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderDecodeScaleFactor; + +// These options are for image encoding +/** + A Boolean value indicating whether to encode the first frame only for animated image during encoding. (NSNumber). If not provide, encode animated image if need. + @note works for `SDWebImageCoder`. + */ +FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeFirstFrameOnly; /** A double value between 0.0-1.0 indicating the encode compression quality to produce the image data. If not provide, use 1.0. (NSNumber) + @note works for `SDWebImageCoder` */ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeCompressionQuality; +#pragma mark - Coder /** This is the image coder protocol to provide custom image decoding/encoding. These methods are all required to implement. @@ -46,6 +59,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp /** Decode the image data to image. + @note This protocol may supports decode animated image frames. You can use `+[SDWebImageCoderHelper animatedImageWithFrames:]` to produce an animated image with frames. @param data The image data to be decoded @param options A dictionary containing any decoding options. Pass @{SDWebImageCoderDecodeFirstFrameOnly: @(YES)} to decode the first frame only. @@ -66,6 +80,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp /** Encode the image to image data. + @note This protocol may supports encode animated image frames. You can use `+[SDWebImageCoderHelper framesFromAnimatedImage:]` to assemble an animated image with frames. @param image The image to be encoded @param format The image format to encode, you should note `SDImageFormatUndefined` format is also possible @@ -78,7 +93,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp @end - +#pragma mark - Progressive Coder /** This is the image coder protocol to provide custom progressive image decoding. These methods are all required to implement. @@ -99,9 +114,10 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp Because incremental decoding need to keep the decoded context, we will alloc a new instance with the same class for each download operation to avoid conflicts This init method should not return nil + @param options A dictionary containing any progressive decoding options (instance-level). Currentlly there is no options for this and always pass nil. Kept for extensibility. @return A new instance to do incremental decoding for the specify image format */ -- (nonnull instancetype)initIncremental; +- (nonnull instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options; /** Update the incremental decoding when new image data available @@ -113,14 +129,16 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp /** Incremental decode the current image data to image. + @note Due to the performance issue for progressive decoding and the integration for image view. This method may only return the first frame image even if the image data is animated image. If you want progressive animated image decoding, also conform to `SDWebImageAnimatedCoder` and use `animatedImageFrameAtIndex` instead. - @param options A dictionary containing any decoding options. + @param options A dictionary containing any progressive decoding options. Pass @{SDWebImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for progressive image @return The decoded image from current data */ - (nullable UIImage *)incrementalDecodedImageWithOptions:(nullable SDWebImageCoderOptions *)options; @end +#pragma mark - Animated Image Provider /** This is the animated image protocol to provide the basic function for animated image rendering. It's adopted by `SDAnimatedImage` and `SDWebImageAnimatedCoder` */ @@ -167,6 +185,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp @end +#pragma mark - Animated Coder /** This is the animated image coder protocol for custom animated image class like `SDAnimatedImage`. Through it inherit from `SDWebImageCoder`. We currentlly only use the method `canDecodeFromData:` to detect the proper coder for specify animated image format. */ @@ -176,11 +195,12 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp /** Because animated image coder should keep the original data, we will alloc a new instance with the same class for the specify animated image data The init method should return nil if it can't decode the specify animated image data to produce any frame. - After the instance created, we may call methods in `SDAnimatedImage` to produce animated image frame. + After the instance created, we may call methods in `SDAnimatedImageProvider` to produce animated image frame. @param data The animated image data to be decode + @param options A dictionary containing any animated decoding options (instance-level). Pass @{SDWebImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for animated image (each frames should use the same scale). @return A new instance to do animated decoding for specify image data */ -- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data; +- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data options:(nullable SDWebImageCoderOptions *)options; @end diff --git a/SDWebImage/SDWebImageCoder.m b/SDWebImage/SDWebImageCoder.m index c7efce68..2778ea3c 100644 --- a/SDWebImage/SDWebImageCoder.m +++ b/SDWebImage/SDWebImageCoder.m @@ -10,4 +10,6 @@ SDWebImageCoderOption const SDWebImageCoderDecodeFirstFrameOnly = @"decodeFirstFrameOnly"; SDWebImageCoderOption const SDWebImageCoderDecodeScaleFactor = @"decodeScaleFactor"; + +SDWebImageCoderOption const SDWebImageCoderEncodeFirstFrameOnly = @"encodeFirstFrameOnly"; SDWebImageCoderOption const SDWebImageCoderEncodeCompressionQuality = @"encodeCompressionQuality"; diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 7dd973b4..3b2cd0f0 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -352,7 +352,7 @@ didReceiveResponse:(NSURLResponse *)response for (idcoder in [SDWebImageCodersManager sharedManager].coders) { if ([coder conformsToProtocol:@protocol(SDWebImageProgressiveCoder)] && [((id)coder) canIncrementalDecodeFromData:imageData]) { - self.progressiveCoder = [[[coder class] alloc] initIncremental]; + self.progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:nil]; break; } } diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index 43e646a3..4b95b7bb 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -28,6 +28,7 @@ size_t _width, _height; CGImageSourceRef _imageSource; NSData *_imageData; + CGFloat _scale; NSUInteger _loopCount; NSUInteger _frameCount; NSArray *_frames; @@ -179,7 +180,7 @@ return ([NSData sd_imageFormatForImageData:data] == SDImageFormatGIF); } -- (instancetype)initIncremental { +- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options { self = [super init]; if (self) { _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)}); @@ -275,7 +276,9 @@ compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue]; } [properties setValue:@(compressionQuality) forKey:(__bridge_transfer NSString *)kCGImageDestinationLossyCompressionQuality]; - if (frames.count == 0) { + + BOOL encodeFirstFrame = [options[SDWebImageCoderEncodeFirstFrameOnly] boolValue]; + if (encodeFirstFrame || frames.count == 0) { // for static single GIF images CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); } else { @@ -305,7 +308,7 @@ } #pragma mark - SDWebImageAnimatedCoder -- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data { +- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data options:(nullable SDWebImageCoderOptions *)options { if (!data) { return nil; } @@ -321,6 +324,14 @@ CFRelease(imageSource); return nil; } + CGFloat scale = 1; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if (scale < 1) { + scale = 1; + } + } + _scale = scale; _imageSource = imageSource; _imageData = data; #if SD_UIKIT @@ -384,9 +395,9 @@ CGImageRelease(imageRef); } #if SD_MAC - UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:1]; + UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale]; #else - UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef]; + UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale orientation:UIImageOrientationUp]; #endif CGImageRelease(newImageRef); return image; diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index 47e622df..92101d25 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -107,7 +107,7 @@ } #pragma mark - Progressive Decode -- (instancetype)initIncremental { +- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options { self = [super init]; if (self) { _imageSource = CGImageSourceCreateIncremental(NULL); diff --git a/SDWebImage/SDWebImageWebPCoder.m b/SDWebImage/SDWebImageWebPCoder.m index 2c91178d..4d18d7bf 100644 --- a/SDWebImage/SDWebImageWebPCoder.m +++ b/SDWebImage/SDWebImageWebPCoder.m @@ -51,6 +51,7 @@ dispatch_semaphore_signal(self->_lock); WebPIDecoder *_idec; WebPDemuxer *_demux; NSData *_imageData; + CGFloat _scale; NSUInteger _loopCount; NSUInteger _frameCount; NSArray *_frames; @@ -205,7 +206,7 @@ dispatch_semaphore_signal(self->_lock); } #pragma mark - Progressive Decode -- (instancetype)initIncremental { +- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options { self = [super init]; if (self) { // Progressive images need transparent, so always use premultiplied RGBA @@ -421,7 +422,9 @@ dispatch_semaphore_signal(self->_lock); compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue]; } NSArray *frames = [SDWebImageCoderHelper framesFromAnimatedImage:image]; - if (frames.count == 0) { + + BOOL encodeFirstFrame = [options[SDWebImageCoderEncodeFirstFrameOnly] boolValue]; + if (encodeFirstFrame || frames.count == 0) { // for static single webp image data = [self sd_encodedWebpDataWithImage:image quality:compressionQuality]; } else { @@ -516,7 +519,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { } #pragma mark - SDWebImageAnimatedCoder -- (instancetype)initWithAnimatedImageData:(NSData *)data { +- (instancetype)initWithAnimatedImageData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { if (!data) { return nil; } @@ -534,6 +537,14 @@ static void FreeImageData(void *info, const void *data, size_t size) { WebPDemuxDelete(demuxer); return nil; } + CGFloat scale = 1; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if (scale < 1) { + scale = 1; + } + } + _scale = scale; _demux = demuxer; _imageData = data; _currentBlendIndex = NSNotFound; @@ -667,9 +678,9 @@ static void FreeImageData(void *info, const void *data, size_t size) { return nil; } #if SD_UIKIT || SD_WATCH - image = [[UIImage alloc] initWithCGImage:imageRef]; + image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:UIImageOrientationUp]; #else - image = [[UIImage alloc] initWithCGImage:imageRef scale:1]; + image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale]; #endif CGImageRelease(imageRef); } else { @@ -697,9 +708,9 @@ static void FreeImageData(void *info, const void *data, size_t size) { return nil; } #if SD_UIKIT || SD_WATCH - image = [[UIImage alloc] initWithCGImage:imageRef]; + image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:UIImageOrientationUp]; #else - image = [[UIImage alloc] initWithCGImage:imageRef scale:1]; + image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale]; #endif CGImageRelease(imageRef); } diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index b3127a24..add6c40a 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -17,6 +17,13 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop count +// Internal header +@interface SDAnimatedImageView () + +@property (nonatomic, assign) BOOL isProgressive; + +@end + @interface SDAnimatedImageTest : SDTestCase @property (nonatomic, strong) UIWindow *window; @@ -55,7 +62,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun - (void)test03AnimatedImageInitWithAnimatedCoder { NSData *validData = [self testGIFData]; - SDWebImageGIFCoder *coder = [[SDWebImageGIFCoder alloc] initWithAnimatedImageData:validData]; + SDWebImageGIFCoder *coder = [[SDWebImageGIFCoder alloc] initWithAnimatedImageData:validData options:nil]; SDAnimatedImage *image = [[SDAnimatedImage alloc] initWithAnimatedCoder:coder scale:1]; expect(image).notTo.beNil(); // enough, other can be test with InitWithData @@ -134,7 +141,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun - (void)test09AnimatedImageViewSetProgressiveAnimatedImage { NSData *gifData = [self testGIFData]; - SDWebImageGIFCoder *progressiveCoder = [[SDWebImageGIFCoder alloc] initIncremental]; + SDWebImageGIFCoder *progressiveCoder = [[SDWebImageGIFCoder alloc] initIncrementalWithOptions:nil]; // simulate progressive decode, pass partial data NSData *partialData = [gifData subdataWithRange:NSMakeRange(0, gifData.length - 1)]; [progressiveCoder updateIncrementalData:partialData finished:NO]; @@ -145,7 +152,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun SDAnimatedImageView *imageView = [[SDAnimatedImageView alloc] init]; imageView.image = partialImage; - BOOL isProgressive = [[imageView valueForKey:@"isProgressive"] boolValue]; + BOOL isProgressive = imageView.isProgressive; expect(isProgressive).equal(YES); // pass full data @@ -155,7 +162,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun imageView.image = fullImage; - isProgressive = [[imageView valueForKey:@"isProgressive"] boolValue]; + isProgressive = imageView.isProgressive; expect(isProgressive).equal(NO); } @@ -182,7 +189,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun // Progressive image may be nil when download data is not enough if (image) { expect(image.sd_isIncremental).beTruthy(); - BOOL isProgressive = [[imageView valueForKey:@"isProgressive"] boolValue]; + BOOL isProgressive = imageView.isProgressive; expect(isProgressive).equal(YES); } }); diff --git a/Tests/Tests/SDWebImageTestDecoder.m b/Tests/Tests/SDWebImageTestDecoder.m index 1ccd5043..feda04ae 100644 --- a/Tests/Tests/SDWebImageTestDecoder.m +++ b/Tests/Tests/SDWebImageTestDecoder.m @@ -25,7 +25,7 @@ return image; } -- (instancetype)initIncremental +- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options { self = [super init]; if (self) { From 0705a973be4c8679a397cbf86096f06f7f3579c7 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 9 Apr 2018 14:16:35 +0800 Subject: [PATCH 104/361] Update to import sd_isDecoded to avoid extra decode. And change exif orientation to CGImagePropertyOrientation define --- SDWebImage/SDWebImageCoderHelper.h | 6 ++-- SDWebImage/SDWebImageCoderHelper.m | 48 ++++++++++++++++------------- SDWebImage/SDWebImageImageIOCoder.m | 4 +-- SDWebImage/UIImage+ForceDecode.h | 5 +++ SDWebImage/UIImage+ForceDecode.m | 10 ++++++ SDWebImage/UIImage+WebCache.h | 2 +- 6 files changed, 47 insertions(+), 28 deletions(-) diff --git a/SDWebImage/SDWebImageCoderHelper.h b/SDWebImage/SDWebImageCoderHelper.h index 4a4cbd31..f582a400 100644 --- a/SDWebImage/SDWebImageCoderHelper.h +++ b/SDWebImage/SDWebImageCoderHelper.h @@ -6,7 +6,7 @@ * file that was distributed with this source code. */ -#import +#import #import "SDWebImageCompat.h" #import "SDWebImageFrame.h" @@ -90,7 +90,7 @@ @param exifOrientation EXIF orientation @return iOS orientation */ -+ (UIImageOrientation)imageOrientationFromEXIFOrientation:(NSInteger)exifOrientation NS_SWIFT_NAME(imageOrientation(from:)); ++ (UIImageOrientation)imageOrientationFromEXIFOrientation:(CGImagePropertyOrientation)exifOrientation NS_SWIFT_NAME(imageOrientation(from:)); /** Convert an iOS orientation to an EXIF image orientation. @@ -98,7 +98,7 @@ @param imageOrientation iOS orientation @return EXIF orientation */ -+ (NSInteger)exifOrientationFromImageOrientation:(UIImageOrientation)imageOrientation; ++ (CGImagePropertyOrientation)exifOrientationFromImageOrientation:(UIImageOrientation)imageOrientation; #endif @end diff --git a/SDWebImage/SDWebImageCoderHelper.m b/SDWebImage/SDWebImageCoderHelper.m index 472d1ee6..6d22c4dd 100644 --- a/SDWebImage/SDWebImageCoderHelper.m +++ b/SDWebImage/SDWebImageCoderHelper.m @@ -10,8 +10,8 @@ #import "SDWebImageFrame.h" #import "NSImage+Additions.h" #import "NSData+ImageContentType.h" -#import #import "SDAnimatedImageRep.h" +#import "UIImage+ForceDecode.h" #if SD_UIKIT || SD_WATCH static const size_t kBytesPerPixel = 4; @@ -286,6 +286,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over } UIImage *decodedImage = [[UIImage alloc] initWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation]; CGImageRelease(imageRef); + decodedImage.sd_isDecoded = YES; return decodedImage; #endif } @@ -414,6 +415,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over if (destImage == nil) { return image; } + destImage.sd_isDecoded = YES; return destImage; } #endif @@ -421,32 +423,31 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over #if SD_UIKIT || SD_WATCH // Convert an EXIF image orientation to an iOS one. -+ (UIImageOrientation)imageOrientationFromEXIFOrientation:(NSInteger)exifOrientation { - // CGImagePropertyOrientation is available on iOS 8 above. Currently kept for compatibility ++ (UIImageOrientation)imageOrientationFromEXIFOrientation:(CGImagePropertyOrientation)exifOrientation { UIImageOrientation imageOrientation = UIImageOrientationUp; switch (exifOrientation) { - case 1: + case kCGImagePropertyOrientationUp: imageOrientation = UIImageOrientationUp; break; - case 3: + case kCGImagePropertyOrientationDown: imageOrientation = UIImageOrientationDown; break; - case 8: + case kCGImagePropertyOrientationLeft: imageOrientation = UIImageOrientationLeft; break; - case 6: + case kCGImagePropertyOrientationRight: imageOrientation = UIImageOrientationRight; break; - case 2: + case kCGImagePropertyOrientationUpMirrored: imageOrientation = UIImageOrientationUpMirrored; break; - case 4: + case kCGImagePropertyOrientationDownMirrored: imageOrientation = UIImageOrientationDownMirrored; break; - case 5: + case kCGImagePropertyOrientationLeftMirrored: imageOrientation = UIImageOrientationLeftMirrored; break; - case 7: + case kCGImagePropertyOrientationRightMirrored: imageOrientation = UIImageOrientationRightMirrored; break; default: @@ -456,33 +457,32 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over } // Convert an iOS orientation to an EXIF image orientation. -+ (NSInteger)exifOrientationFromImageOrientation:(UIImageOrientation)imageOrientation { - // CGImagePropertyOrientation is available on iOS 8 above. Currently kept for compatibility - NSInteger exifOrientation = 1; ++ (CGImagePropertyOrientation)exifOrientationFromImageOrientation:(UIImageOrientation)imageOrientation { + CGImagePropertyOrientation exifOrientation = kCGImagePropertyOrientationUp; switch (imageOrientation) { case UIImageOrientationUp: - exifOrientation = 1; + exifOrientation = kCGImagePropertyOrientationUp; break; case UIImageOrientationDown: - exifOrientation = 3; + exifOrientation = kCGImagePropertyOrientationDown; break; case UIImageOrientationLeft: - exifOrientation = 8; + exifOrientation = kCGImagePropertyOrientationLeft; break; case UIImageOrientationRight: - exifOrientation = 6; + exifOrientation = kCGImagePropertyOrientationRight; break; case UIImageOrientationUpMirrored: - exifOrientation = 2; + exifOrientation = kCGImagePropertyOrientationUpMirrored; break; case UIImageOrientationDownMirrored: - exifOrientation = 4; + exifOrientation = kCGImagePropertyOrientationDownMirrored; break; case UIImageOrientationLeftMirrored: - exifOrientation = 5; + exifOrientation = kCGImagePropertyOrientationLeftMirrored; break; case UIImageOrientationRightMirrored: - exifOrientation = 7; + exifOrientation = kCGImagePropertyOrientationRightMirrored; break; default: break; @@ -494,6 +494,10 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over #pragma mark - Helper Fuction #if SD_UIKIT || SD_WATCH + (BOOL)shouldDecodeImage:(nullable UIImage *)image { + // Avoid extra decode + if (image.sd_isDecoded) { + return NO; + } // Prevent "CGBitmapContextCreateImage: invalid context 0x0" error if (image == nil) { return NO; diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index 92101d25..b068fa02 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -148,7 +148,7 @@ // oriented incorrectly sometimes. (Unlike the image born of initWithData // in didCompleteWithError.) So save it here and pass it on later. #if SD_UIKIT || SD_WATCH - _orientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:orientationValue]; + _orientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:(CGImagePropertyOrientation)orientationValue]; #endif } } @@ -327,7 +327,7 @@ val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation); if (val) { CFNumberGetValue(val, kCFNumberNSIntegerType, &exifOrientation); - result = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:exifOrientation]; + result = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:(CGImagePropertyOrientation)exifOrientation]; } // else - if it's not set it remains at up CFRelease((CFTypeRef) properties); } diff --git a/SDWebImage/UIImage+ForceDecode.h b/SDWebImage/UIImage+ForceDecode.h index ae85114b..0911a54c 100644 --- a/SDWebImage/UIImage+ForceDecode.h +++ b/SDWebImage/UIImage+ForceDecode.h @@ -10,6 +10,11 @@ @interface UIImage (ForceDecode) +/** + A bool value indicating whether the image has already been decoded. This can help to avoid extra force decode. + */ +@property (nonatomic, assign) BOOL sd_isDecoded; + /** Decompress (force decode before rendering) the provided image diff --git a/SDWebImage/UIImage+ForceDecode.m b/SDWebImage/UIImage+ForceDecode.m index 3edc796a..3ddd2078 100644 --- a/SDWebImage/UIImage+ForceDecode.m +++ b/SDWebImage/UIImage+ForceDecode.m @@ -8,9 +8,19 @@ #import "UIImage+ForceDecode.h" #import "SDWebImageCoderHelper.h" +#import "objc/runtime.h" @implementation UIImage (ForceDecode) +- (BOOL)sd_isDecoded { + NSNumber *value = objc_getAssociatedObject(self, @selector(sd_isDecoded)); + return value.boolValue; +} + +- (void)setSd_isDecoded:(BOOL)sd_isDecoded { + objc_setAssociatedObject(self, @selector(sd_isDecoded), @(sd_isDecoded), OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + + (UIImage *)sd_decodedImageWithImage:(UIImage *)image { if (!image) { return nil; diff --git a/SDWebImage/UIImage+WebCache.h b/SDWebImage/UIImage+WebCache.h index b7991976..b53b17bb 100644 --- a/SDWebImage/UIImage+WebCache.h +++ b/SDWebImage/UIImage+WebCache.h @@ -30,7 +30,7 @@ @property (nonatomic, assign, readonly) BOOL sd_isAnimated; /** - Indicating whether the image is during incremental decoding and may not contains full pixels. + A bool value indicating whether the image is during incremental decoding and may not contains full pixels. */ @property (nonatomic, assign) BOOL sd_isIncremental; From 8801138fb258f88abb5fd9e51a8beae17b32f893 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Tue, 10 Apr 2018 13:54:19 +0300 Subject: [PATCH 105/361] Updated README.md to reflect the 5.x changes to the supported platforms and backward compatibility --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6976ecaf..92858518 100644 --- a/README.md +++ b/README.md @@ -33,15 +33,17 @@ This library provides an async image downloader with cache support. For convenie ## Requirements -- iOS 7.0 or later +- iOS 8.0 or later - tvOS 9.0 or later - watchOS 2.0 or later -- macOS 10.9 or later +- macOS 10.10 or later - Xcode 7.3 or later #### Backwards compatibility -- For iOS 5 and 6, use [any 3.x version up to 3.7.6](https://github.com/rs/SDWebImage/tree/3.7.6) +- For iOS 7 and macOS 10.9, use [any 4.x version up to 4.3.3](https://github.com/rs/SDWebImage/releases/tag/4.3.3) +- For macOS 10.8, use [any 4.x version up to 4.3.0](https://github.com/rs/SDWebImage/releases/tag/4.3.0) +- For iOS 5 and 6, use [any 3.x version up to 3.7.6](https://github.com/rs/SDWebImage/tag/3.7.6) - For iOS < 5.0, please use the last [2.0 version](https://github.com/rs/SDWebImage/tree/2.0-compat). ## Getting Started From b9ec481edf94da61ed8e8f5fcdf73c1e303a5dc0 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 10 Apr 2018 17:40:08 +0800 Subject: [PATCH 106/361] Remove the extra calculation of image orientation for ImageIO coder --- SDWebImage/SDWebImageImageIOCoder.m | 36 ---------------------------- Tests/Tests/SDWebImageDecoderTests.m | 14 ----------- 2 files changed, 50 deletions(-) diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index b068fa02..35cdb150 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -90,20 +90,7 @@ } UIImage *image = [[UIImage alloc] initWithData:data scale:scale]; -#if SD_MAC return image; -#else - if (!image) { - return nil; - } - - UIImageOrientation orientation = [[self class] sd_imageOrientationFromImageData:data]; - if (orientation != UIImageOrientationUp) { - image = [[UIImage alloc] initWithCGImage:image.CGImage scale:image.scale orientation:orientation]; - } - - return image; -#endif } #pragma mark - Progressive Decode @@ -314,27 +301,4 @@ return canEncode; } -#if SD_UIKIT || SD_WATCH -#pragma mark EXIF orientation tag converter -+ (UIImageOrientation)sd_imageOrientationFromImageData:(nonnull NSData *)imageData { - UIImageOrientation result = UIImageOrientationUp; - CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL); - if (imageSource) { - CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL); - if (properties) { - CFTypeRef val; - NSInteger exifOrientation; - val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation); - if (val) { - CFNumberGetValue(val, kCFNumberNSIntegerType, &exifOrientation); - result = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:(CGImagePropertyOrientation)exifOrientation]; - } // else - if it's not set it remains at up - CFRelease((CFTypeRef) properties); - } - CFRelease(imageSource); - } - return result; -} -#endif - @end diff --git a/Tests/Tests/SDWebImageDecoderTests.m b/Tests/Tests/SDWebImageDecoderTests.m index a3fd4cea..7b14dead 100644 --- a/Tests/Tests/SDWebImageDecoderTests.m +++ b/Tests/Tests/SDWebImageDecoderTests.m @@ -87,20 +87,6 @@ expect(decodedImage.size.width).to.equal(image.size.width); expect(decodedImage.size.height).to.equal(image.size.height); } - -- (void)test08ImageOrientationFromImageDataWithInvalidData { - // sync download image -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wundeclared-selector" - SEL selector = @selector(sd_imageOrientationFromImageData:); -#pragma clang diagnostic pop - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - UIImageOrientation orientation = (UIImageOrientation)[[SDWebImageImageIOCoder class] performSelector:selector withObject:nil]; -#pragma clang diagnostic pop - expect(orientation).to.equal(UIImageOrientationUp); -} #endif - (void)test09ThatStaticWebPCoderWorks { From acbdb8c3747feac0ccbd7a2e9cf6461c194860a8 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 10 Apr 2018 20:44:26 +0800 Subject: [PATCH 107/361] Add helper method in coder helper to create decoded CGImage to specify orientation. The existing method just call with Up orientation --- SDWebImage/SDWebImageCoderHelper.h | 11 +++++ SDWebImage/SDWebImageCoderHelper.m | 77 +++++++++++++++++++++++++++++- 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/SDWebImage/SDWebImageCoderHelper.h b/SDWebImage/SDWebImageCoderHelper.h index f582a400..689bd74d 100644 --- a/SDWebImage/SDWebImageCoderHelper.h +++ b/SDWebImage/SDWebImageCoderHelper.h @@ -61,12 +61,23 @@ /** Create a decoded image by the provided image. This follows The Create Rule and you are response to call release after usage. It will detect whether image contains alpha channel, then create a new bitmap context with the same size of image, and draw it. This can ensure that the image do not need extra decoding after been set to the imageView. + @note This actually call `imageRefCreateDecoded:orientation` with the Up orientation. @param imageRef The CGImage @return A new created decoded image */ + (CGImageRef _Nullable)imageRefCreateDecoded:(_Nonnull CGImageRef)imageRef CF_RETURNS_RETAINED; +/** + Create a decoded image by the provided image. This follows The Create Rule and you are response to call release after usage. + It will detect whether image contains alpha channel, then create a new bitmap context with the same size of image, and draw it. This can ensure that the image do not need extra decoding after been set to the imageView. + + @param imageRef The CGImage + @param orientation The image orientation. + @return A new created decoded image + */ ++ (CGImageRef _Nullable)imageRefCreateDecoded:(_Nonnull CGImageRef)imageRef orientation:(CGImagePropertyOrientation)orientation CF_RETURNS_RETAINED; + /** Return the decoded image by the provided image. This one unlike `imageRefCreateDecoded:`, will not decode the image which contains alpha channel or animated image @param image The image to be decoded diff --git a/SDWebImage/SDWebImageCoderHelper.m b/SDWebImage/SDWebImageCoderHelper.m index 6d22c4dd..fda81231 100644 --- a/SDWebImage/SDWebImageCoderHelper.m +++ b/SDWebImage/SDWebImageCoderHelper.m @@ -248,13 +248,16 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over } + (CGImageRef)imageRefCreateDecoded:(CGImageRef)imageRef { + return [self imageRefCreateDecoded:imageRef orientation:kCGImagePropertyOrientationUp]; +} + ++ (CGImageRef)imageRefCreateDecoded:(CGImageRef)imageRef orientation:(CGImagePropertyOrientation)orientation { if (!imageRef) { return NULL; } size_t width = CGImageGetWidth(imageRef); size_t height = CGImageGetHeight(imageRef); if (width == 0 || height == 0) return NULL; - CGRect rect = CGRectMake(0, 0, width, height); BOOL hasAlpha = [self imageRefContainsAlpha:imageRef]; // iOS prefer BGRA8888 (premultiplied) or BGRX8888 bitmapInfo for screen rendering, which is same as `UIGraphicsBeginImageContext()` or `- [CALayer drawInContext:]` // Through you can use any supported bitmapInfo (see: https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html#//apple_ref/doc/uid/TP30001066-CH203-BCIBHHBB ) and let Core Graphics reorder it when you call `CGContextDrawImage` @@ -265,6 +268,25 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over if (!context) { return NULL; } + + // Apply transform + CGAffineTransform transform = SDCGContextTransformFromOrientation(orientation, CGSizeMake(width, height)); + CGRect rect; + switch (orientation) { + case kCGImagePropertyOrientationLeft: + case kCGImagePropertyOrientationLeftMirrored: + case kCGImagePropertyOrientationRight: + case kCGImagePropertyOrientationRightMirrored: { + // These orientation should swap width & height + rect = CGRectMake(0, 0, height, width); + } + break; + default: { + rect = CGRectMake(0, 0, width, height); + } + break; + } + CGContextConcatCTM(context, transform); CGContextDrawImage(context, rect, imageRef); CGImageRef newImageRef = CGBitmapContextCreateImage(context); CGContextRelease(context); @@ -546,7 +568,60 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over return shouldScaleDown; } +#endif +static CGAffineTransform SDCGContextTransformFromOrientation(CGImagePropertyOrientation orientation, CGSize size) { + // Inspiration from @libfeihu + // We need to calculate the proper transformation to make the image upright. + // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. + CGAffineTransform transform = CGAffineTransformIdentity; + + switch (orientation) { + case kCGImagePropertyOrientationDown: + case kCGImagePropertyOrientationDownMirrored: + transform = CGAffineTransformTranslate(transform, size.width, size.height); + transform = CGAffineTransformRotate(transform, M_PI); + break; + + case kCGImagePropertyOrientationLeft: + case kCGImagePropertyOrientationLeftMirrored: + transform = CGAffineTransformTranslate(transform, size.width, 0); + transform = CGAffineTransformRotate(transform, M_PI_2); + break; + + case kCGImagePropertyOrientationRight: + case kCGImagePropertyOrientationRightMirrored: + transform = CGAffineTransformTranslate(transform, 0, size.height); + transform = CGAffineTransformRotate(transform, -M_PI_2); + break; + case kCGImagePropertyOrientationUp: + case kCGImagePropertyOrientationUpMirrored: + break; + } + + switch (orientation) { + case kCGImagePropertyOrientationUpMirrored: + case kCGImagePropertyOrientationDownMirrored: + transform = CGAffineTransformTranslate(transform, size.width, 0); + transform = CGAffineTransformScale(transform, -1, 1); + break; + + case kCGImagePropertyOrientationLeftMirrored: + case kCGImagePropertyOrientationRightMirrored: + transform = CGAffineTransformTranslate(transform, size.height, 0); + transform = CGAffineTransformScale(transform, -1, 1); + break; + case kCGImagePropertyOrientationUp: + case kCGImagePropertyOrientationDown: + case kCGImagePropertyOrientationLeft: + case kCGImagePropertyOrientationRight: + break; + } + + return transform; +} + +#if SD_UIKIT || SD_WATCH static NSUInteger gcd(NSUInteger a, NSUInteger b) { NSUInteger c; while (a != 0) { From 7d50d61b3721bf3be3d4dd892821fdfdda88e386 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 10 Apr 2018 21:18:53 +0800 Subject: [PATCH 108/361] Update the NSImage+Addtions to allow specify a image orientation when using `CGImage`. Update all the place we use --- Examples/SDWebImage OSX Demo/ViewController.m | 2 +- SDWebImage/NSImage+Additions.h | 15 ++-- SDWebImage/NSImage+Additions.m | 68 ++++++++++++++++--- SDWebImage/SDAnimatedImage.m | 2 +- SDWebImage/SDWebImageAPNGCoder.m | 6 +- SDWebImage/SDWebImageCoderHelper.h | 4 +- SDWebImage/SDWebImageCoderHelper.m | 2 +- SDWebImage/SDWebImageDefine.m | 2 +- SDWebImage/SDWebImageGIFCoder.m | 6 +- SDWebImage/SDWebImageImageIOCoder.m | 14 ++-- SDWebImage/SDWebImageWebPCoder.m | 12 ++-- SDWebImage/UIImage+Transform.m | 14 ++-- 12 files changed, 103 insertions(+), 44 deletions(-) diff --git a/Examples/SDWebImage OSX Demo/ViewController.m b/Examples/SDWebImage OSX Demo/ViewController.m index cb7dbee8..a01af45c 100644 --- a/Examples/SDWebImage OSX Demo/ViewController.m +++ b/Examples/SDWebImage OSX Demo/ViewController.m @@ -32,7 +32,7 @@ self.imageView3.animates = YES; self.imageView4.animates = YES; self.imageView1.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator; - [self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"]]; + [self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"https://raw.githubusercontent.com/recurser/exif-orientation-examples/master/Landscape_2.jpg"] placeholderImage:nil options:SDWebImageProgressiveDownload]; [self.imageView2 sd_setImageWithURL:[NSURL URLWithString:@"https:raw.githubusercontent.com/onevcat/APNGKit/master/TestImages/APNG-cube.apng"]]; [self.imageView3 sd_setImageWithURL:[NSURL URLWithString:@"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"]]; self.imageView4.wantsLayer = YES; diff --git a/SDWebImage/NSImage+Additions.h b/SDWebImage/NSImage+Additions.h index 08aad12b..d575bc1e 100644 --- a/SDWebImage/NSImage+Additions.h +++ b/SDWebImage/NSImage+Additions.h @@ -19,21 +19,23 @@ The underlying Core Graphics image object. This will actually `CGImageForPropose */ @property (nonatomic, readonly, nullable) CGImageRef CGImage; /** - The scale factor of the image. This wil actually use image size, and its `CGImage`'s pixel size to calculate the scale factor. Should be greater than or equal to 1.0. + The scale factor of the image. This wil actually use bitmap representation's size and pixel size to calculate the scale factor. If failed, use the default value 1.0. Should be greater than or equal to 1.0. */ @property (nonatomic, readonly) CGFloat scale; // These are convenience methods to make AppKit's `NSImage` match UIKit's `UIImage` behavior. The scale factor should be greater than or equal to 1.0. /** - Returns an image object with the scale factor. The representation is created from the Core Graphics image object. + Returns an image object with the scale factor and orientation. The representation is created from the Core Graphics image object. @note The difference between this and `initWithCGImage:size` is that `initWithCGImage:size` will create a `NSCGImageSnapshotRep` but not `NSBitmapImageRep` instance. And it will always `backingScaleFactor` as scale factor. + @note If the provided image orientation is not equal to Up orientation. This method will firstly rotate the CGImage to the correct orientation to work compatible with `NSImageView`. @param cgImage A Core Graphics image object @param scale The image scale factor + @param orientation The orientation of the image data @return The image object */ -- (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale; +- (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation; /** Returns an image object with the scale factor. The representation is created from the image data. @@ -49,8 +51,11 @@ The underlying Core Graphics image object. This will actually `CGImageForPropose @interface NSBitmapImageRep (Additions) -// These method's function is the same as `NSImage`'s function. For `NSBitmapImageRep`. -- (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale; +// These methods' function is the same as `NSImage`'s function. For `NSBitmapImageRep`. + +@property (nonatomic, readonly) CGFloat scale; + +- (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation; - (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale; @end diff --git a/SDWebImage/NSImage+Additions.m b/SDWebImage/NSImage+Additions.m index 984aa0fd..a880b21c 100644 --- a/SDWebImage/NSImage+Additions.m +++ b/SDWebImage/NSImage+Additions.m @@ -10,6 +10,9 @@ #if SD_MAC +#import "SDWebImageCoderHelper.h" +#import "objc/runtime.h" + @implementation NSImage (Additions) - (CGImageRef)CGImage { @@ -20,21 +23,29 @@ - (CGFloat)scale { CGFloat scale = 1; - CGFloat width = self.size.width; - if (width > 0) { - // Use CGImage to get pixel width, NSImageRep.pixelsWide may be double on Retina screen - NSUInteger pixelWidth = CGImageGetWidth(self.CGImage); - scale = pixelWidth / width; + NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); + NSImageRep *imageRep = [self bestRepresentationForRect:imageRect context:nil hints:nil]; + NSBitmapImageRep *bitmapImageRep; + if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) { + bitmapImageRep = (NSBitmapImageRep *)imageRep; } + if (bitmapImageRep) { + return bitmapImageRep.scale; + } + return scale; } - (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale { + return [self initWithCGImage:cgImage scale:scale orientation:kCGImagePropertyOrientationUp]; +} + +- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation { if (scale < 1) { scale = 1; } - NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage scale:scale]; - NSSize size = NSMakeSize(imageRep.pixelsWide / scale, imageRep.pixelsHigh / scale); + NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage scale:scale orientation:orientation]; + NSSize size = imageRep.size; self = [self initWithSize:size]; if (self) { [self addRepresentation:imageRep]; @@ -50,7 +61,7 @@ if (!imageRep) { return nil; } - NSSize size = NSMakeSize(imageRep.pixelsWide / scale, imageRep.pixelsHigh / scale); + NSSize size = imageRep.size; self = [self initWithSize:size]; if (self) { [self addRepresentation:imageRep]; @@ -60,10 +71,47 @@ @end +@interface NSBitmapImageRep () + +@property (nonatomic, assign, readonly, nullable) CGImageSourceRef imageSource; + +@end + @implementation NSBitmapImageRep (Additions) -- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale { - self = [self initWithCGImage:cgImage]; +- (CGImageSourceRef)imageSource { + if (_tiffData) { + return (__bridge CGImageSourceRef)(_tiffData); + } + return NULL; +} + +- (CGFloat)scale { + CGFloat scale = 1; + CGFloat width = self.size.width; + CGFloat height = self.size.height; + NSUInteger pixelWidth = self.pixelsWide; + NSUInteger pixelHeight = self.pixelsHigh; + if (width > 0 && height > 0) { + CGFloat widthScale = pixelWidth / width; + CGFloat heightScale = pixelHeight / height; + if (widthScale == heightScale && widthScale >= 1) { + // Protect for image object which custom the size. + scale = widthScale; + } + } + return scale; +} + +- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation { + if (orientation != kCGImagePropertyOrientationUp) { + // This should be nonnull, until the memory is exhausted cause `CGBitmapContextCreate` failed. + cgImage = [SDWebImageCoderHelper imageRefCreateDecoded:cgImage orientation:orientation]; + self = [self initWithCGImage:cgImage]; + CGImageRelease(cgImage); + } else { + self = [self initWithCGImage:cgImage]; + } if (self) { if (scale < 1) { scale = 1; diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index 6a715658..74e16784 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -310,7 +310,7 @@ static NSArray *SDBundlePreferredScales() { return nil; } #if SD_MAC - self = [super initWithCGImage:image.CGImage scale:scale]; + self = [super initWithCGImage:image.CGImage scale:scale orientation:kCGImagePropertyOrientationUp]; #else self = [super initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; #endif diff --git a/SDWebImage/SDWebImageAPNGCoder.m b/SDWebImage/SDWebImageAPNGCoder.m index c3bb1e82..5b9d8c5d 100644 --- a/SDWebImage/SDWebImageAPNGCoder.m +++ b/SDWebImage/SDWebImageAPNGCoder.m @@ -299,8 +299,8 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef } #if SD_UIKIT || SD_WATCH image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:UIImageOrientationUp]; -#elif SD_MAC - image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale]; +#else + image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:kCGImagePropertyOrientationUp]; #endif CGImageRelease(partialImageRef); } @@ -403,7 +403,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef CGImageRelease(imageRef); } #if SD_MAC - UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale]; + UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale orientation:kCGImagePropertyOrientationUp]; #else UIImage *image = [UIImage imageWithCGImage:newImageRef scale:_scale orientation:UIImageOrientationUp]; #endif diff --git a/SDWebImage/SDWebImageCoderHelper.h b/SDWebImage/SDWebImageCoderHelper.h index 689bd74d..b4551258 100644 --- a/SDWebImage/SDWebImageCoderHelper.h +++ b/SDWebImage/SDWebImageCoderHelper.h @@ -59,7 +59,7 @@ + (BOOL)imageRefContainsAlpha:(_Nonnull CGImageRef)imageRef; /** - Create a decoded image by the provided image. This follows The Create Rule and you are response to call release after usage. + Create a decoded CGImage by the provided CGImage. This follows The Create Rule and you are response to call release after usage. It will detect whether image contains alpha channel, then create a new bitmap context with the same size of image, and draw it. This can ensure that the image do not need extra decoding after been set to the imageView. @note This actually call `imageRefCreateDecoded:orientation` with the Up orientation. @@ -69,7 +69,7 @@ + (CGImageRef _Nullable)imageRefCreateDecoded:(_Nonnull CGImageRef)imageRef CF_RETURNS_RETAINED; /** - Create a decoded image by the provided image. This follows The Create Rule and you are response to call release after usage. + Create a decoded CGImage by the provided CGImage and orientation. This follows The Create Rule and you are response to call release after usage. It will detect whether image contains alpha channel, then create a new bitmap context with the same size of image, and draw it. This can ensure that the image do not need extra decoding after been set to the imageView. @param imageRef The CGImage diff --git a/SDWebImage/SDWebImageCoderHelper.m b/SDWebImage/SDWebImageCoderHelper.m index fda81231..4ac5d379 100644 --- a/SDWebImage/SDWebImageCoderHelper.m +++ b/SDWebImage/SDWebImageCoderHelper.m @@ -183,7 +183,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over // NSBitmapImageRep need to manually change frame. "Good taste" API [bitmapImageRep setProperty:NSImageCurrentFrame withValue:@(i)]; float frameDuration = [[bitmapImageRep valueForProperty:NSImageCurrentFrameDuration] floatValue]; - NSImage *frameImage = [[NSImage alloc] initWithCGImage:bitmapImageRep.CGImage scale:scale]; + NSImage *frameImage = [[NSImage alloc] initWithCGImage:bitmapImageRep.CGImage scale:scale orientation:kCGImagePropertyOrientationUp]; SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:frameImage duration:frameDuration]; [frames addObject:frame]; } diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m index 35b518e4..d16d90d4 100644 --- a/SDWebImage/SDWebImageDefine.m +++ b/SDWebImage/SDWebImageDefine.m @@ -106,7 +106,7 @@ inline UIImage * _Nullable SDScaledImageForScaleFactor(CGFloat scale, UIImage * #if SD_UIKIT || SD_WATCH scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; #else - scaledImage = [[NSImage alloc] initWithCGImage:image.CGImage scale:scale]; + scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:kCGImagePropertyOrientationUp]; #endif } scaledImage.sd_isIncremental = image.sd_isIncremental; diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index 4b95b7bb..278aee17 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -236,8 +236,8 @@ } #if SD_UIKIT || SD_WATCH image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:UIImageOrientationUp]; -#elif SD_MAC - image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale]; +#else + image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:kCGImagePropertyOrientationUp]; #endif CGImageRelease(partialImageRef); } @@ -395,7 +395,7 @@ CGImageRelease(imageRef); } #if SD_MAC - UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale]; + UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale orientation:kCGImagePropertyOrientationUp]; #else UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale orientation:UIImageOrientationUp]; #endif diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index 35cdb150..0b9946a4 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -16,6 +16,8 @@ size_t _width, _height; #if SD_UIKIT || SD_WATCH UIImageOrientation _orientation; +#else + CGImagePropertyOrientation _orientation; #endif CGImageSourceRef _imageSource; NSUInteger _frameCount; @@ -136,6 +138,8 @@ // in didCompleteWithError.) So save it here and pass it on later. #if SD_UIKIT || SD_WATCH _orientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:(CGImagePropertyOrientation)orientationValue]; +#else + _orientation = (CGImagePropertyOrientation)orientationValue; #endif } } @@ -177,8 +181,8 @@ } #if SD_UIKIT || SD_WATCH image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:_orientation]; -#elif SD_MAC - image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale]; +#else + image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:_orientation]; #endif CGImageRelease(partialImageRef); } @@ -227,9 +231,11 @@ NSMutableDictionary *properties = [NSMutableDictionary dictionary]; #if SD_UIKIT || SD_WATCH - NSInteger exifOrientation = [SDWebImageCoderHelper exifOrientationFromImageOrientation:image.imageOrientation]; - [properties setValue:@(exifOrientation) forKey:(__bridge_transfer NSString *)kCGImagePropertyOrientation]; + CGImagePropertyOrientation exifOrientation = [SDWebImageCoderHelper exifOrientationFromImageOrientation:image.imageOrientation]; +#else + CGImagePropertyOrientation exifOrientation = kCGImagePropertyOrientationUp; #endif + [properties setValue:@(exifOrientation) forKey:(__bridge_transfer NSString *)kCGImagePropertyOrientation]; double compressionQuality = 1; if ([options valueForKey:SDWebImageCoderEncodeCompressionQuality]) { compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue]; diff --git a/SDWebImage/SDWebImageWebPCoder.m b/SDWebImage/SDWebImageWebPCoder.m index 4d18d7bf..89ea48d1 100644 --- a/SDWebImage/SDWebImageWebPCoder.m +++ b/SDWebImage/SDWebImageWebPCoder.m @@ -131,7 +131,7 @@ dispatch_semaphore_signal(self->_lock); #if SD_UIKIT || SD_WATCH UIImage *staticImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; #else - UIImage *staticImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale]; + UIImage *staticImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp]; #endif CGImageRelease(imageRef); WebPDemuxDelete(demuxer); @@ -153,7 +153,7 @@ dispatch_semaphore_signal(self->_lock); #if SD_UIKIT || SD_WATCH UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; #else - UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale]; + UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp]; #endif CGImageRelease(imageRef); WebPDemuxReleaseIterator(&iter); @@ -184,7 +184,7 @@ dispatch_semaphore_signal(self->_lock); #if SD_UIKIT || SD_WATCH UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; #else - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale]; + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp]; #endif CGImageRelease(imageRef); @@ -289,7 +289,7 @@ dispatch_semaphore_signal(self->_lock); #if SD_UIKIT || SD_WATCH image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale orientation:UIImageOrientationUp]; #else - image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale]; + image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale orientation:kCGImagePropertyOrientationUp]; #endif CGImageRelease(newImageRef); CGContextRelease(canvas); @@ -680,7 +680,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { #if SD_UIKIT || SD_WATCH image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:UIImageOrientationUp]; #else - image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale]; + image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:kCGImagePropertyOrientationUp]; #endif CGImageRelease(imageRef); } else { @@ -710,7 +710,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { #if SD_UIKIT || SD_WATCH image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:UIImageOrientationUp]; #else - image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale]; + image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:kCGImagePropertyOrientationUp]; #endif CGImageRelease(imageRef); } diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 847a2682..530a1a57 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -90,7 +90,7 @@ static UIImage * SDGraphicsGetImageFromCurrentImageContext(void) { // Protect if x/y axis scale factor not equal scale = [NSScreen mainScreen].backingScaleFactor; } - NSImage *image = [[NSImage alloc] initWithCGImage:imageRef scale:scale]; + NSImage *image = [[NSImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp]; CGImageRelease(imageRef); return image; #endif @@ -322,7 +322,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation]; #else - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale]; + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale orientation:kCGImagePropertyOrientationUp]; #endif CGImageRelease(imageRef); return image; @@ -400,7 +400,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH UIImage *img = [UIImage imageWithCGImage:imgRef scale:self.scale orientation:self.imageOrientation]; #else - UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale]; + UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale orientation:kCGImagePropertyOrientationUp]; #endif CGImageRelease(imgRef); CGContextRelease(context); @@ -436,7 +436,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH UIImage *img = [UIImage imageWithCGImage:imgRef scale:self.scale orientation:self.imageOrientation]; #else - UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale]; + UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale orientation:kCGImagePropertyOrientationUp]; #endif CGImageRelease(imgRef); return img; @@ -453,7 +453,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH return [UIImage imageWithCGImage:self.CGImage scale:self.scale orientation:self.imageOrientation]; #else - return [[UIImage alloc] initWithCGImage:self.CGImage scale:self.scale]; + return [[UIImage alloc] initWithCGImage:self.CGImage scale:self.scale orientation:kCGImagePropertyOrientationUp]; #endif } @@ -670,7 +670,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT || SD_WATCH UIImage *outputImage = [UIImage imageWithCGImage:effectCGImage scale:self.scale orientation:self.imageOrientation]; #else - UIImage *outputImage = [[UIImage alloc] initWithCGImage:effectCGImage scale:self.scale]; + UIImage *outputImage = [[UIImage alloc] initWithCGImage:effectCGImage scale:self.scale orientation:kCGImagePropertyOrientationUp]; #endif CGImageRelease(effectCGImage); @@ -695,7 +695,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma #if SD_UIKIT UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation]; #else - UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale]; + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale orientation:kCGImagePropertyOrientationUp]; #endif CGImageRelease(imageRef); From cebf72d6d58e002275bcc257617d2299339ad216 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 11 Apr 2018 08:16:39 +0800 Subject: [PATCH 109/361] Refactor API. Change that `imageRef` arg description to `CGImage` to match the common design pattern and make it clear to Swift user --- SDWebImage/NSImage+Additions.h | 12 +++---- SDWebImage/NSImage+Additions.m | 50 ++++++++--------------------- SDWebImage/SDImageCache.m | 2 +- SDWebImage/SDWebImageAPNGCoder.m | 2 +- SDWebImage/SDWebImageCoder.h | 2 +- SDWebImage/SDWebImageCoderHelper.h | 28 ++++++---------- SDWebImage/SDWebImageCoderHelper.m | 28 ++++++++-------- SDWebImage/SDWebImageGIFCoder.m | 2 +- SDWebImage/SDWebImageImageIOCoder.m | 2 +- 9 files changed, 47 insertions(+), 81 deletions(-) diff --git a/SDWebImage/NSImage+Additions.h b/SDWebImage/NSImage+Additions.h index d575bc1e..0b2cb669 100644 --- a/SDWebImage/NSImage+Additions.h +++ b/SDWebImage/NSImage+Additions.h @@ -15,11 +15,11 @@ @interface NSImage (Additions) /** -The underlying Core Graphics image object. This will actually `CGImageForProposedRect` with the image size. +The underlying Core Graphics image object. This will actually use `CGImageForProposedRect` with the image size. */ @property (nonatomic, readonly, nullable) CGImageRef CGImage; /** - The scale factor of the image. This wil actually use bitmap representation's size and pixel size to calculate the scale factor. If failed, use the default value 1.0. Should be greater than or equal to 1.0. + The scale factor of the image. This wil actually use `bestRepresentationForRect` with image size and pixel size to calculate the scale factor. If failed, use the default value 1.0. Should be greater than or equal to 1.0. */ @property (nonatomic, readonly) CGFloat scale; @@ -27,8 +27,8 @@ The underlying Core Graphics image object. This will actually `CGImageForPropose /** Returns an image object with the scale factor and orientation. The representation is created from the Core Graphics image object. - @note The difference between this and `initWithCGImage:size` is that `initWithCGImage:size` will create a `NSCGImageSnapshotRep` but not `NSBitmapImageRep` instance. And it will always `backingScaleFactor` as scale factor. - @note If the provided image orientation is not equal to Up orientation. This method will firstly rotate the CGImage to the correct orientation to work compatible with `NSImageView`. + @note The difference between this and `initWithCGImage:size` is that `initWithCGImage:size` will create a `NSCGImageSnapshotRep` but not `NSBitmapImageRep` instance. And it will always use `backingScaleFactor` as scale factor. + @note The difference between this and UIKit's `UIImage` equivalent method is the way to process orientation. If the provided image orientation is not equal to Up orientation, this method will firstly rotate the CGImage to the correct orientation to work compatible with `NSImageView`. However, UIKit will not actually rotate CGImage and just store it as `imageOrientation` property. @param cgImage A Core Graphics image object @param scale The image scale factor @@ -39,7 +39,7 @@ The underlying Core Graphics image object. This will actually `CGImageForPropose /** Returns an image object with the scale factor. The representation is created from the image data. - @note The difference between these this and `initWithData:` is that `initWithData:` will always `backingScaleFactor` as scale factor. + @note The difference between these this and `initWithData:` is that `initWithData:` will always use `backingScaleFactor` as scale factor. @param data The image data @param scale The image scale factor @@ -53,8 +53,6 @@ The underlying Core Graphics image object. This will actually `CGImageForPropose // These methods' function is the same as `NSImage`'s function. For `NSBitmapImageRep`. -@property (nonatomic, readonly) CGFloat scale; - - (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation; - (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale; diff --git a/SDWebImage/NSImage+Additions.m b/SDWebImage/NSImage+Additions.m index a880b21c..37a7827d 100644 --- a/SDWebImage/NSImage+Additions.m +++ b/SDWebImage/NSImage+Additions.m @@ -25,12 +25,17 @@ CGFloat scale = 1; NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); NSImageRep *imageRep = [self bestRepresentationForRect:imageRect context:nil hints:nil]; - NSBitmapImageRep *bitmapImageRep; - if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) { - bitmapImageRep = (NSBitmapImageRep *)imageRep; - } - if (bitmapImageRep) { - return bitmapImageRep.scale; + CGFloat width = imageRep.size.width; + CGFloat height = imageRep.size.height; + NSUInteger pixelWidth = imageRep.pixelsWide; + NSUInteger pixelHeight = imageRep.pixelsHigh; + if (width > 0 && height > 0) { + CGFloat widthScale = pixelWidth / width; + CGFloat heightScale = pixelHeight / height; + if (widthScale == heightScale && widthScale >= 1) { + // Protect for image object which custom the size. + scale = widthScale; + } } return scale; @@ -71,42 +76,13 @@ @end -@interface NSBitmapImageRep () - -@property (nonatomic, assign, readonly, nullable) CGImageSourceRef imageSource; - -@end - @implementation NSBitmapImageRep (Additions) -- (CGImageSourceRef)imageSource { - if (_tiffData) { - return (__bridge CGImageSourceRef)(_tiffData); - } - return NULL; -} - -- (CGFloat)scale { - CGFloat scale = 1; - CGFloat width = self.size.width; - CGFloat height = self.size.height; - NSUInteger pixelWidth = self.pixelsWide; - NSUInteger pixelHeight = self.pixelsHigh; - if (width > 0 && height > 0) { - CGFloat widthScale = pixelWidth / width; - CGFloat heightScale = pixelHeight / height; - if (widthScale == heightScale && widthScale >= 1) { - // Protect for image object which custom the size. - scale = widthScale; - } - } - return scale; -} - - (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation { if (orientation != kCGImagePropertyOrientationUp) { + // AppKit design is different from UIKit. Where CGImage based image rep does not respect to any orientation. Only data based image rep which contains the EXIF metadata can automatically detect orientation. // This should be nonnull, until the memory is exhausted cause `CGBitmapContextCreate` failed. - cgImage = [SDWebImageCoderHelper imageRefCreateDecoded:cgImage orientation:orientation]; + cgImage = [SDWebImageCoderHelper CGImageCreateDecoded:cgImage orientation:orientation]; self = [self initWithCGImage:cgImage]; CGImageRelease(cgImage); } else { diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 180352e4..fc0e50f3 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -297,7 +297,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (!data && image) { // If we do not have any data to detect image format, check whether it contains alpha channel to use PNG or JPEG format SDImageFormat format; - if ([SDWebImageCoderHelper imageRefContainsAlpha:image.CGImage]) { + if ([SDWebImageCoderHelper CGImageContainsAlpha:image.CGImage]) { format = SDImageFormatPNG; } else { format = SDImageFormatJPEG; diff --git a/SDWebImage/SDWebImageAPNGCoder.m b/SDWebImage/SDWebImageAPNGCoder.m index 5b9d8c5d..c6b694c3 100644 --- a/SDWebImage/SDWebImageAPNGCoder.m +++ b/SDWebImage/SDWebImageAPNGCoder.m @@ -396,7 +396,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef return nil; } // Image/IO create CGImage does not decompressed, so we do this because this is called background queue, this can avoid main queue block when rendering(especially when one more imageViews use the same image instance) - CGImageRef newImageRef = [SDWebImageCoderHelper imageRefCreateDecoded:imageRef]; + CGImageRef newImageRef = [SDWebImageCoderHelper CGImageCreateDecoded:imageRef]; if (!newImageRef) { newImageRef = imageRef; } else { diff --git a/SDWebImage/SDWebImageCoder.h b/SDWebImage/SDWebImageCoder.h index de73401c..a0297477 100644 --- a/SDWebImage/SDWebImageCoder.h +++ b/SDWebImage/SDWebImageCoder.h @@ -33,7 +33,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderDecodeScal */ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeFirstFrameOnly; /** - A double value between 0.0-1.0 indicating the encode compression quality to produce the image data. If not provide, use 1.0. (NSNumber) + A double value between 0.0-1.0 indicating the encode compression quality to produce the image data. 1.0 resulting in no compression and 0.0 resulting in the maximum compression possible. If not provide, use 1.0. (NSNumber) @note works for `SDWebImageCoder` */ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeCompressionQuality; diff --git a/SDWebImage/SDWebImageCoderHelper.h b/SDWebImage/SDWebImageCoderHelper.h index b4551258..30acfbf4 100644 --- a/SDWebImage/SDWebImageCoderHelper.h +++ b/SDWebImage/SDWebImageCoderHelper.h @@ -33,7 +33,7 @@ + (NSArray * _Nullable)framesFromAnimatedImage:(UIImage * _Nullable)animatedImage NS_SWIFT_NAME(frames(from:)); /** - Return the shared device-dependent RGB color space. + Return the shared device-dependent RGB color space. This follows The Get Rule. On iOS, it's created with deviceRGB (if available, use sRGB). On macOS, it's from the screen colorspace (if failed, use deviceRGB) Because it's shared, you should not retain or release this object. @@ -42,44 +42,36 @@ */ + (CGColorSpaceRef _Nonnull)colorSpaceGetDeviceRGB CF_RETURNS_NOT_RETAINED; -/** - Retuen the color space of the CGImage - - @param imageRef The CGImage - @return The color space of CGImage, or if not supported, return the device-dependent RGB color space - */ -+ (CGColorSpaceRef _Nonnull)imageRefGetColorSpace:(_Nonnull CGImageRef)imageRef CF_RETURNS_NOT_RETAINED; - /** Check whether CGImage contains alpha channel. - @param imageRef The CGImage + @param cgImage The CGImage @return Return YES if CGImage contains alpha channel, otherwise return NO */ -+ (BOOL)imageRefContainsAlpha:(_Nonnull CGImageRef)imageRef; ++ (BOOL)CGImageContainsAlpha:(_Nonnull CGImageRef)cgImage; /** Create a decoded CGImage by the provided CGImage. This follows The Create Rule and you are response to call release after usage. It will detect whether image contains alpha channel, then create a new bitmap context with the same size of image, and draw it. This can ensure that the image do not need extra decoding after been set to the imageView. - @note This actually call `imageRefCreateDecoded:orientation` with the Up orientation. + @note This actually call `CGImageCreateDecoded:orientation:` with the Up orientation. - @param imageRef The CGImage + @param cgImage The CGImage @return A new created decoded image */ -+ (CGImageRef _Nullable)imageRefCreateDecoded:(_Nonnull CGImageRef)imageRef CF_RETURNS_RETAINED; ++ (CGImageRef _Nullable)CGImageCreateDecoded:(_Nonnull CGImageRef)cgImage CF_RETURNS_RETAINED; /** Create a decoded CGImage by the provided CGImage and orientation. This follows The Create Rule and you are response to call release after usage. It will detect whether image contains alpha channel, then create a new bitmap context with the same size of image, and draw it. This can ensure that the image do not need extra decoding after been set to the imageView. - @param imageRef The CGImage - @param orientation The image orientation. + @param cgImage The CGImage + @param orientation The EXIF image orientation. @return A new created decoded image */ -+ (CGImageRef _Nullable)imageRefCreateDecoded:(_Nonnull CGImageRef)imageRef orientation:(CGImagePropertyOrientation)orientation CF_RETURNS_RETAINED; ++ (CGImageRef _Nullable)CGImageCreateDecoded:(_Nonnull CGImageRef)cgImage orientation:(CGImagePropertyOrientation)orientation CF_RETURNS_RETAINED; /** - Return the decoded image by the provided image. This one unlike `imageRefCreateDecoded:`, will not decode the image which contains alpha channel or animated image + Return the decoded image by the provided image. This one unlike `CGImageCreateDecoded:`, will not decode the image which contains alpha channel or animated image @param image The image to be decoded @return The decoded image */ diff --git a/SDWebImage/SDWebImageCoderHelper.m b/SDWebImage/SDWebImageCoderHelper.m index 4ac5d379..43c10212 100644 --- a/SDWebImage/SDWebImageCoderHelper.m +++ b/SDWebImage/SDWebImageCoderHelper.m @@ -236,29 +236,29 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over return colorspaceRef; } -+ (BOOL)imageRefContainsAlpha:(CGImageRef)imageRef { - if (!imageRef) { ++ (BOOL)CGImageContainsAlpha:(CGImageRef)cgImage { + if (!cgImage) { return NO; } - CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef); + CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(cgImage); BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone || alphaInfo == kCGImageAlphaNoneSkipFirst || alphaInfo == kCGImageAlphaNoneSkipLast); return hasAlpha; } -+ (CGImageRef)imageRefCreateDecoded:(CGImageRef)imageRef { - return [self imageRefCreateDecoded:imageRef orientation:kCGImagePropertyOrientationUp]; ++ (CGImageRef)CGImageCreateDecoded:(CGImageRef)cgImage { + return [self CGImageCreateDecoded:cgImage orientation:kCGImagePropertyOrientationUp]; } -+ (CGImageRef)imageRefCreateDecoded:(CGImageRef)imageRef orientation:(CGImagePropertyOrientation)orientation { - if (!imageRef) { ++ (CGImageRef)CGImageCreateDecoded:(CGImageRef)cgImage orientation:(CGImagePropertyOrientation)orientation { + if (!cgImage) { return NULL; } - size_t width = CGImageGetWidth(imageRef); - size_t height = CGImageGetHeight(imageRef); + size_t width = CGImageGetWidth(cgImage); + size_t height = CGImageGetHeight(cgImage); if (width == 0 || height == 0) return NULL; - BOOL hasAlpha = [self imageRefContainsAlpha:imageRef]; + BOOL hasAlpha = [self CGImageContainsAlpha:cgImage]; // iOS prefer BGRA8888 (premultiplied) or BGRX8888 bitmapInfo for screen rendering, which is same as `UIGraphicsBeginImageContext()` or `- [CALayer drawInContext:]` // Through you can use any supported bitmapInfo (see: https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html#//apple_ref/doc/uid/TP30001066-CH203-BCIBHHBB ) and let Core Graphics reorder it when you call `CGContextDrawImage` // But since our build-in coders use this bitmapInfo, this can have a little performance benefit @@ -287,7 +287,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over break; } CGContextConcatCTM(context, transform); - CGContextDrawImage(context, rect, imageRef); + CGContextDrawImage(context, rect, cgImage); CGImageRef newImageRef = CGBitmapContextCreateImage(context); CGContextRelease(context); @@ -302,7 +302,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over return image; } - CGImageRef imageRef = [self imageRefCreateDecoded:image.CGImage]; + CGImageRef imageRef = [self CGImageCreateDecoded:image.CGImage]; if (!imageRef) { return image; } @@ -529,7 +529,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over return NO; } CGImageRef imageRef = image.CGImage; - BOOL hasAlpha = [self imageRefContainsAlpha:imageRef]; + BOOL hasAlpha = [self CGImageContainsAlpha:imageRef]; // do not decode images with alpha if (hasAlpha) { return NO; @@ -570,7 +570,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over } #endif -static CGAffineTransform SDCGContextTransformFromOrientation(CGImagePropertyOrientation orientation, CGSize size) { +static inline CGAffineTransform SDCGContextTransformFromOrientation(CGImagePropertyOrientation orientation, CGSize size) { // Inspiration from @libfeihu // We need to calculate the proper transformation to make the image upright. // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index 278aee17..3db33284 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -388,7 +388,7 @@ return nil; } // Image/IO create CGImage does not decode, so we do this because this is called background queue, this can avoid main queue block when rendering(especially when one more imageViews use the same image instance) - CGImageRef newImageRef = [SDWebImageCoderHelper imageRefCreateDecoded:imageRef]; + CGImageRef newImageRef = [SDWebImageCoderHelper CGImageCreateDecoded:imageRef]; if (!newImageRef) { newImageRef = imageRef; } else { diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index 0b9946a4..cc7feda5 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -211,7 +211,7 @@ } if (format == SDImageFormatUndefined) { - BOOL hasAlpha = [SDWebImageCoderHelper imageRefContainsAlpha:image.CGImage]; + BOOL hasAlpha = [SDWebImageCoderHelper CGImageContainsAlpha:image.CGImage]; if (hasAlpha) { format = SDImageFormatPNG; } else { From e2c99f437dc9e4989fecd19cebcd85dfd6dc10f0 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 11 Apr 2018 12:42:15 +0800 Subject: [PATCH 110/361] Remove the extra category method for `NSBitmapImageRep`. Only use `NSImage`'s native API to manage it --- SDWebImage/NSImage+Additions.h | 11 +----- SDWebImage/NSImage+Additions.m | 70 +++++++++------------------------- 2 files changed, 20 insertions(+), 61 deletions(-) diff --git a/SDWebImage/NSImage+Additions.h b/SDWebImage/NSImage+Additions.h index 0b2cb669..b7fdcd64 100644 --- a/SDWebImage/NSImage+Additions.h +++ b/SDWebImage/NSImage+Additions.h @@ -27,7 +27,7 @@ The underlying Core Graphics image object. This will actually use `CGImageForPro /** Returns an image object with the scale factor and orientation. The representation is created from the Core Graphics image object. - @note The difference between this and `initWithCGImage:size` is that `initWithCGImage:size` will create a `NSCGImageSnapshotRep` but not `NSBitmapImageRep` instance. And it will always use `backingScaleFactor` as scale factor. + @note The difference between this and `initWithCGImage:size` is that `initWithCGImage:size` will use `backingScaleFactor` as scale factor if you specify `NSZeroSize` and does not support orientation. @note The difference between this and UIKit's `UIImage` equivalent method is the way to process orientation. If the provided image orientation is not equal to Up orientation, this method will firstly rotate the CGImage to the correct orientation to work compatible with `NSImageView`. However, UIKit will not actually rotate CGImage and just store it as `imageOrientation` property. @param cgImage A Core Graphics image object @@ -49,13 +49,4 @@ The underlying Core Graphics image object. This will actually use `CGImageForPro @end -@interface NSBitmapImageRep (Additions) - -// These methods' function is the same as `NSImage`'s function. For `NSBitmapImageRep`. - -- (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation; -- (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale; - -@end - #endif diff --git a/SDWebImage/NSImage+Additions.m b/SDWebImage/NSImage+Additions.m index 37a7827d..dc68fdca 100644 --- a/SDWebImage/NSImage+Additions.m +++ b/SDWebImage/NSImage+Additions.m @@ -11,7 +11,6 @@ #if SD_MAC #import "SDWebImageCoderHelper.h" -#import "objc/runtime.h" @implementation NSImage (Additions) @@ -33,7 +32,7 @@ CGFloat widthScale = pixelWidth / width; CGFloat heightScale = pixelHeight / height; if (widthScale == heightScale && widthScale >= 1) { - // Protect for image object which custom the size. + // Protect because there may be `NSImageRepMatchesDevice` (0) scale = widthScale; } } @@ -41,71 +40,40 @@ return scale; } -- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale { - return [self initWithCGImage:cgImage scale:scale orientation:kCGImagePropertyOrientationUp]; -} - - (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation { if (scale < 1) { scale = 1; } - NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage scale:scale orientation:orientation]; - NSSize size = imageRep.size; - self = [self initWithSize:size]; - if (self) { - [self addRepresentation:imageRep]; - } - return self; -} - -- (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale { - if (scale < 1) { - scale = 1; - } - NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithData:data scale:scale]; - if (!imageRep) { - return nil; - } - NSSize size = imageRep.size; - self = [self initWithSize:size]; - if (self) { - [self addRepresentation:imageRep]; - } - return self; -} - -@end - -@implementation NSBitmapImageRep (Additions) - -- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation { + CGFloat pixelWidth = CGImageGetWidth(cgImage); + CGFloat pixelHeight = CGImageGetHeight(cgImage); + NSSize size = NSMakeSize(pixelWidth / scale, pixelHeight / scale); if (orientation != kCGImagePropertyOrientationUp) { // AppKit design is different from UIKit. Where CGImage based image rep does not respect to any orientation. Only data based image rep which contains the EXIF metadata can automatically detect orientation. // This should be nonnull, until the memory is exhausted cause `CGBitmapContextCreate` failed. cgImage = [SDWebImageCoderHelper CGImageCreateDecoded:cgImage orientation:orientation]; - self = [self initWithCGImage:cgImage]; + self = [self initWithCGImage:cgImage size:size]; CGImageRelease(cgImage); } else { - self = [self initWithCGImage:cgImage]; - } - if (self) { - if (scale < 1) { - scale = 1; - } - NSSize size = NSMakeSize(self.pixelsWide / scale, self.pixelsHigh / scale); - self.size = size; + self = [self initWithCGImage:cgImage size:size]; } return self; } - (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale { - self = [self initWithData:data]; + NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithData:data]; + if (!imageRep) { + return nil; + } + if (scale < 1) { + scale = 1; + } + CGFloat pixelWidth = imageRep.pixelsWide; + CGFloat pixelHeight = imageRep.pixelsHigh; + NSSize size = NSMakeSize(pixelWidth / scale, pixelHeight / scale); + self = [self initWithSize:size]; if (self) { - if (scale < 1) { - scale = 1; - } - NSSize size = NSMakeSize(self.pixelsWide / scale, self.pixelsHigh / scale); - self.size = size; + imageRep.size = size; + [self addRepresentation:imageRep]; } return self; } From a710bc547275bb0311a45b5f356e2313562f764c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 12 Apr 2018 01:19:06 +0800 Subject: [PATCH 111/361] Fix two warnings about losing precision in comparison --- SDWebImage/SDWebImageDownloaderOperation.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 20196e1f..49cd50cc 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -46,7 +46,7 @@ typedef NSMutableDictionary SDCallbacksDictionary; @property (strong, nonatomic, nullable) NSMutableData *imageData; @property (copy, nonatomic, nullable) NSData *cachedData; // for `SDWebImageDownloaderIgnoreCachedResponse` @property (copy, nonatomic, nullable) NSString *cacheKey; -@property (assign, nonatomic, readwrite) long long expectedSize; +@property (assign, nonatomic, readwrite) NSUInteger expectedSize; @property (strong, nonatomic, nullable, readwrite) NSURLResponse *response; // This is weak because it is injected by whoever manages this session. If this gets nil-ed out, we won't be able to run @@ -343,7 +343,7 @@ didReceiveResponse:(NSURLResponse *)response // Get the image data __block NSData *imageData = [self.imageData copy]; // Get the total bytes downloaded - const NSInteger totalSize = imageData.length; + const NSUInteger totalSize = imageData.length; // Get the finish status BOOL finished = (totalSize >= self.expectedSize); From 7701215ae097947b1953d891e4ac99de7bfcd511 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 13 Apr 2018 01:03:11 +0800 Subject: [PATCH 112/361] Fix the bug that reset indicator view does not remove from super view --- SDWebImage/UIView+WebCache.m | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 921d1017..a651b9ec 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -296,15 +296,16 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; } - (void)setSd_imageIndicator:(id)sd_imageIndicator { + // Remove the old indicator view id previousIndicator = self.sd_imageIndicator; - if (previousIndicator == sd_imageIndicator) { - [previousIndicator.indicatorView removeFromSuperview]; - } + [previousIndicator.indicatorView removeFromSuperview]; + + objc_setAssociatedObject(self, @selector(sd_imageIndicator), sd_imageIndicator, OBJC_ASSOCIATION_RETAIN_NONATOMIC); // Add the new indicator view UIView *view = sd_imageIndicator.indicatorView; if (CGRectEqualToRect(view.frame, CGRectZero)) { - view.frame = self.frame; + view.frame = self.bounds; } // Center the indicator view #if SD_MAC @@ -316,8 +317,6 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; #endif view.hidden = NO; [self addSubview:view]; - - objc_setAssociatedObject(self, @selector(sd_imageIndicator), sd_imageIndicator, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (void)sd_startImageIndicator { From b9773d09c04427765c74b6e06431dabc0420c199 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 13 Apr 2018 02:15:18 +0800 Subject: [PATCH 113/361] Fix SDGetColorFromPixel ignore kCGImageAlphaOnly case --- SDWebImage/UIImage+Transform.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 530a1a57..1ba361eb 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -232,7 +232,11 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma } } break; - case kCGImageAlphaOnly: + case kCGImageAlphaOnly: { + // A + a = pixel[0]; + } + break; default: break; } From e829637a30d2ad9599bbcc3a9ad499ae0f01edf3 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 13 Apr 2018 02:34:52 +0800 Subject: [PATCH 114/361] Update to use scale factor instead of that firstFrameOnly, since it's not used frequently as scale --- SDWebImage/UIImage+MultiFormat.h | 9 ++++----- SDWebImage/UIImage+MultiFormat.m | 9 ++++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/SDWebImage/UIImage+MultiFormat.h b/SDWebImage/UIImage+MultiFormat.h index c66ae83c..ff4b9ee8 100644 --- a/SDWebImage/UIImage+MultiFormat.h +++ b/SDWebImage/UIImage+MultiFormat.h @@ -13,7 +13,6 @@ #pragma mark - Decode /** Create and decode a image with the specify image data - If the image data is animated image format, create an animated image if possible @param data The image data @return The created image @@ -21,13 +20,13 @@ + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data; /** - Create and decode a image with the specify image data + Create and decode a image with the specify image data and scale @param data The image data - @param firstFrameOnly Even if the image data is animated image format, decode the first frame only + @param scale The image scale factor. Should be greater than or equal to 1.0. @return The created image */ -+ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data firstFrameOnly:(BOOL)firstFrameOnly; ++ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data scale:(CGFloat)scale; #pragma mark - Encode /** @@ -46,7 +45,7 @@ - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat; /** - Encode the current image to data with the specify image format + Encode the current image to data with the specify image format and compression quality @param imageFormat The specify image format @param compressionQuality The quality of the resulting image data. Value between 0.0-1.0. Some coders may not support compression quality. diff --git a/SDWebImage/UIImage+MultiFormat.m b/SDWebImage/UIImage+MultiFormat.m index 846bd167..b0145bc8 100644 --- a/SDWebImage/UIImage+MultiFormat.m +++ b/SDWebImage/UIImage+MultiFormat.m @@ -12,14 +12,17 @@ @implementation UIImage (MultiFormat) + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data { - return [self sd_imageWithData:data firstFrameOnly:NO]; + return [self sd_imageWithData:data scale:1]; } -+ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data firstFrameOnly:(BOOL)firstFrameOnly { ++ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data scale:(CGFloat)scale { if (!data) { return nil; } - SDWebImageCoderOptions *options = @{SDWebImageCoderDecodeFirstFrameOnly : @(firstFrameOnly)}; + if (scale < 1) { + scale = 1; + } + SDWebImageCoderOptions *options = @{SDWebImageCoderDecodeScaleFactor : @(scale)}; return [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:options]; } From 25b61bb5ae366dcec40bee7dd645341756f185dd Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 13 Apr 2018 11:10:14 +0800 Subject: [PATCH 115/361] Refactor the cache path API. Only given the full cache path to allow user to choose to use filename or full path. And use a block instead of static array for additional cache path. --- Examples/SDWebImage Demo/AppDelegate.m | 5 ++- SDWebImage/SDImageCache.h | 47 +++++++++++--------------- SDWebImage/SDImageCache.m | 47 ++++++++------------------ 3 files changed, 38 insertions(+), 61 deletions(-) diff --git a/Examples/SDWebImage Demo/AppDelegate.m b/Examples/SDWebImage Demo/AppDelegate.m index a7c47598..8eb070d6 100644 --- a/Examples/SDWebImage Demo/AppDelegate.m +++ b/Examples/SDWebImage Demo/AppDelegate.m @@ -21,7 +21,10 @@ { //Add a custom read-only cache path NSString *bundledPath = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:@"CustomPathImages"]; - [[SDImageCache sharedImageCache] addReadOnlyCachePath:bundledPath]; + [SDImageCache sharedImageCache].additionalCachePathBlock = ^NSString * _Nullable(NSString * _Nonnull key) { + NSString *fileName = [[SDImageCache sharedImageCache] cachePathForKey:key].lastPathComponent; + return [bundledPath stringByAppendingPathComponent:fileName.stringByDeletingPathExtension]; + }; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; // Override point for customization after application launch. diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index ddc93dd0..81b5bc23 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -58,6 +58,8 @@ typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger tot typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable error); +typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * _Nonnull key); + /** * SDImageCache maintains a memory cache and an optional disk cache. Disk cache write operations are performed * asynchronous so it doesn’t add unnecessary latency to the UI. @@ -71,6 +73,18 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er */ @property (nonatomic, nonnull, readonly) SDImageCacheConfig *config; +/** + * The disk cache's root path + */ +@property (nonatomic, copy, nonnull, readonly) NSString *diskCachePath; + +/** + * The additional disk cache path to check if the query from disk cache not exist; + * The `key` param is the image cache key. The returned file path will be used to load the disk cache. If return nil, ignore it. + * Useful if you want to bundle pre-loaded images with your app + */ +@property (nonatomic, copy, nullable) SDImageCacheAdditionalCachePathBlock additionalCachePathBlock; + #pragma mark - Singleton and initialization /** @@ -107,15 +121,13 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er #pragma mark - Cache paths -- (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace; - /** - * Add a read-only cache path to search for images pre-cached by SDImageCache - * Useful if you want to bundle pre-loaded images with your app - * - * @param path The path to use for this read-only cache path + Get the cache path for a certain key + + @param key The unique image cache key + @return The cache path. You can check `lastPathComponent` to grab the file name. */ -- (void)addReadOnlyCachePath:(nonnull NSString *)path; +- (nullable NSString *)cachePathForKey:(nullable NSString *)key; #pragma mark - Store Ops @@ -299,25 +311,4 @@ typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable er */ - (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock; -#pragma mark - Cache Paths - -/** - * Get the cache path for a certain key (needs the cache path root folder) - * - * @param key the key (can be obtained from url using cacheKeyForURL) - * @param path the cache path root folder - * - * @return the cache path - */ -- (nullable NSString *)cachePathForKey:(nullable NSString *)key inPath:(nonnull NSString *)path; - -/** - * Get the default cache path for a certain key - * - * @param key the key (can be obtained from url using cacheKeyForURL) - * - * @return the default cache path - */ -- (nullable NSString *)defaultCachePathForKey:(nullable NSString *)key; - @end diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index fc0e50f3..1b6683c0 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -128,8 +128,6 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { #pragma mark - Properties @property (strong, nonatomic, nonnull) SDMemoryCache *memCache; -@property (strong, nonatomic, nonnull) NSString *diskCachePath; -@property (strong, nonatomic, nullable) NSMutableArray *customPaths; @property (strong, nonatomic, nullable) dispatch_queue_t ioQueue; @property (strong, nonatomic, nonnull) NSFileManager *fileManager; @@ -218,14 +216,11 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { #pragma mark - Cache paths -- (void)addReadOnlyCachePath:(nonnull NSString *)path { - if (!self.customPaths) { - self.customPaths = [NSMutableArray new]; - } - - if (![self.customPaths containsObject:path]) { - [self.customPaths addObject:path]; +- (nullable NSString *)cachePathForKey:(nullable NSString *)key { + if (!key) { + return nil; } + return [self cachePathForKey:key inPath:self.diskCachePath]; } - (nullable NSString *)cachePathForKey:(nullable NSString *)key inPath:(nonnull NSString *)path { @@ -233,10 +228,6 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { return [path stringByAppendingPathComponent:filename]; } -- (nullable NSString *)defaultCachePathForKey:(nullable NSString *)key { - return [self cachePathForKey:key inPath:self.diskCachePath]; -} - - (nullable NSString *)cachedFileNameForKey:(nullable NSString *)key { const char *str = key.UTF8String; if (str == NULL) { @@ -352,7 +343,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } // get cache Path for image key - NSString *cachePathForKey = [self defaultCachePathForKey:key]; + NSString *cachePathForKey = [self cachePathForKey:key]; // transform to NSUrl NSURL *fileURL = [NSURL fileURLWithPath:cachePathForKey]; @@ -402,12 +393,12 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (!key) { return NO; } - BOOL exists = [self.fileManager fileExistsAtPath:[self defaultCachePathForKey:key]]; + BOOL exists = [self.fileManager fileExistsAtPath:[self cachePathForKey:key]]; // fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name // checking the key with and without the extension if (!exists) { - exists = [self.fileManager fileExistsAtPath:[self defaultCachePathForKey:key].stringByDeletingPathExtension]; + exists = [self.fileManager fileExistsAtPath:[self cachePathForKey:key].stringByDeletingPathExtension]; } return exists; @@ -440,7 +431,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } - (nullable NSData *)diskImageDataBySearchingAllPathsForKey:(nullable NSString *)key { - NSString *defaultPath = [self defaultCachePathForKey:key]; + NSString *defaultPath = [self cachePathForKey:key]; NSData *data = [NSData dataWithContentsOfFile:defaultPath options:self.config.diskCacheReadingOptions error:nil]; if (data) { return data; @@ -452,20 +443,12 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (data) { return data; } - - NSArray *customPaths = [self.customPaths copy]; - for (NSString *path in customPaths) { - NSString *filePath = [self cachePathForKey:key inPath:path]; - NSData *imageData = [NSData dataWithContentsOfFile:filePath options:self.config.diskCacheReadingOptions error:nil]; - if (imageData) { - return imageData; - } - - // fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name - // checking the key with and without the extension - imageData = [NSData dataWithContentsOfFile:filePath.stringByDeletingPathExtension options:self.config.diskCacheReadingOptions error:nil]; - if (imageData) { - return imageData; + + // Addtional cache path for custom pre-load cache + if (self.additionalCachePathBlock) { + NSString *filePath = self.additionalCachePathBlock(key); + if (filePath) { + data = [NSData dataWithContentsOfFile:filePath options:self.config.diskCacheReadingOptions error:nil]; } } @@ -616,7 +599,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (fromDisk) { dispatch_async(self.ioQueue, ^{ - [self.fileManager removeItemAtPath:[self defaultCachePathForKey:key] error:nil]; + [self.fileManager removeItemAtPath:[self cachePathForKey:key] error:nil]; if (completion) { dispatch_async(dispatch_get_main_queue(), ^{ From f8e9dd341249661a55a8a45eece7d9753fef3e15 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 13 Apr 2018 11:19:03 +0800 Subject: [PATCH 116/361] Update the test for cache path API --- Tests/Tests/SDImageCacheTests.m | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index 0f5a09fd..4a53c7c2 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -195,13 +195,13 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; [self waitForExpectationsWithCommonTimeout]; } -- (void)test31DefaultCachePathForAnyKey{ - NSString *path = [[SDImageCache sharedImageCache] defaultCachePathForKey:kImageTestKey]; +- (void)test31CachePathForAnyKey{ + NSString *path = [[SDImageCache sharedImageCache] cachePathForKey:kImageTestKey]; expect(path).toNot.beNil; } -- (void)test32CachePathForNonExistingKey{ - NSString *path = [[SDImageCache sharedImageCache] cachePathForKey:kImageTestKey inPath:[[SDImageCache sharedImageCache] defaultCachePathForKey:kImageTestKey]]; +- (void)test32CachePathForNilKey{ + NSString *path = [[SDImageCache sharedImageCache] cachePathForKey:nil]; expect(path).to.beNil; } @@ -209,7 +209,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; XCTestExpectation *expectation = [self expectationWithDescription:@"cachePathForKey inPath"]; [[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:^(NSError * _Nullable error) { expect(error).to.beNil(); - NSString *path = [[SDImageCache sharedImageCache] cachePathForKey:kImageTestKey inPath:[[SDImageCache sharedImageCache] defaultCachePathForKey:kImageTestKey]]; + NSString *path = [[SDImageCache sharedImageCache] cachePathForKey:kImageTestKey]; expect(path).notTo.beNil; [[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{ [expectation fulfill]; @@ -219,14 +219,14 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; } - (void)test34CachePathForSimpleKeyWithExtension { - NSString *cachePath = [[SDImageCache sharedImageCache] cachePathForKey:kTestJpegURL inPath:@""]; + NSString *cachePath = [[SDImageCache sharedImageCache] cachePathForKey:kTestJpegURL]; expect(cachePath).toNot.beNil(); expect([cachePath pathExtension]).to.equal(@"jpg"); } - (void)test35CachePathForKeyWithDotButNoExtension { NSString *urlString = @"https://maps.googleapis.com/maps/api/staticmap?center=48.8566,2.3522&format=png&maptype=roadmap&scale=2&size=375x200&zoom=15"; - NSString *cachePath = [[SDImageCache sharedImageCache] cachePathForKey:urlString inPath:@""]; + NSString *cachePath = [[SDImageCache sharedImageCache] cachePathForKey:urlString]; expect(cachePath).toNot.beNil(); expect([cachePath pathExtension]).to.equal(@""); } @@ -242,7 +242,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; UIImage *storedImageFromMemory = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]; expect(storedImageFromMemory).to.equal(nil); - NSString *cachePath = [[SDImageCache sharedImageCache] defaultCachePathForKey:kImageTestKey]; + NSString *cachePath = [[SDImageCache sharedImageCache] cachePathForKey:kImageTestKey]; UIImage *cachedImage = [[UIImage alloc] initWithContentsOfFile:cachePath]; NSData *storedImageData = UIImageJPEGRepresentation(cachedImage, 1.0); expect(storedImageData.length).to.beGreaterThan(0); From e1d96e7812f97b03db1f2500ef480a398f016e2a Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 13 Apr 2018 16:48:15 +0800 Subject: [PATCH 117/361] Revert "Merge pull request #1898 from walkline/master into 5.x" --- SDWebImage/SDImageCache.h | 14 ++++----- SDWebImage/SDImageCache.m | 52 +++++++++++++-------------------- Tests/Tests/SDImageCacheTests.m | 43 ++++++++------------------- Tests/Tests/SDMockFileManager.h | 2 ++ Tests/Tests/SDMockFileManager.m | 4 +++ 5 files changed, 43 insertions(+), 72 deletions(-) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 81b5bc23..cb5a0f0a 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -56,8 +56,6 @@ typedef void(^SDWebImageCheckCacheCompletionBlock)(BOOL isInCache); typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize); -typedef void(^SDWebImageCompletionWithPossibleErrorBlock)(NSError * _Nullable error); - typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * _Nonnull key); /** @@ -140,7 +138,7 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * */ - (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key - completion:(nullable SDWebImageCompletionWithPossibleErrorBlock)completionBlock; + completion:(nullable SDWebImageNoParamsBlock)completionBlock; /** * Asynchronously store an image into memory and disk cache at the given key. @@ -153,7 +151,7 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * - (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key toDisk:(BOOL)toDisk - completion:(nullable SDWebImageCompletionWithPossibleErrorBlock)completionBlock; + completion:(nullable SDWebImageNoParamsBlock)completionBlock; /** * Asynchronously store an image into memory and disk cache at the given key. @@ -170,18 +168,16 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * imageData:(nullable NSData *)imageData forKey:(nullable NSString *)key toDisk:(BOOL)toDisk - completion:(nullable SDWebImageCompletionWithPossibleErrorBlock)completionBlock; + completion:(nullable SDWebImageNoParamsBlock)completionBlock; /** * Synchronously store image NSData into disk cache at the given key. * * @param imageData The image data to store * @param key The unique image cache key, usually it's image absolute URL - * @param error NSError pointer, for possible file I/O errors, See FoundationErrors.h */ -- (BOOL)storeImageDataToDisk:(nullable NSData *)imageData - forKey:(nullable NSString *)key - error:(NSError * _Nullable * _Nullable)error; +- (void)storeImageDataToDisk:(nullable NSData *)imageData + forKey:(nullable NSString *)key; #pragma mark - Query and Retrieve Ops diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 1b6683c0..c66e7b9b 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -252,14 +252,14 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { - (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key - completion:(nullable SDWebImageCompletionWithPossibleErrorBlock)completionBlock { + completion:(nullable SDWebImageNoParamsBlock)completionBlock { [self storeImage:image imageData:nil forKey:key toDisk:YES completion:completionBlock]; } - (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key toDisk:(BOOL)toDisk - completion:(nullable SDWebImageCompletionWithPossibleErrorBlock)completionBlock { + completion:(nullable SDWebImageNoParamsBlock)completionBlock { [self storeImage:image imageData:nil forKey:key toDisk:toDisk completion:completionBlock]; } @@ -267,10 +267,10 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { imageData:(nullable NSData *)imageData forKey:(nullable NSString *)key toDisk:(BOOL)toDisk - completion:(nullable SDWebImageCompletionWithPossibleErrorBlock)completionBlock { + completion:(nullable SDWebImageNoParamsBlock)completionBlock { if (!image || !key) { if (completionBlock) { - completionBlock(nil); + completionBlock(); } return; } @@ -282,7 +282,6 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (toDisk) { dispatch_async(self.ioQueue, ^{ - NSError * writeError = nil; @autoreleasepool { NSData *data = imageData; if (!data && image) { @@ -295,50 +294,41 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } data = [[SDWebImageCodersManager sharedManager] encodedDataWithImage:image format:format options:nil]; } - [self _storeImageDataToDisk:data forKey:key error:&writeError]; + [self _storeImageDataToDisk:data forKey:key]; } if (completionBlock) { dispatch_async(dispatch_get_main_queue(), ^{ - completionBlock(writeError); + completionBlock(); }); } }); } else { if (completionBlock) { - completionBlock(nil); + completionBlock(); } } } -- (BOOL)storeImageDataToDisk:(nullable NSData *)imageData - forKey:(nullable NSString *)key - error:(NSError * _Nullable __autoreleasing * _Nullable)error { +- (void)storeImageDataToDisk:(nullable NSData *)imageData + forKey:(nullable NSString *)key { if (!imageData || !key) { - return NO; - } - __autoreleasing NSError *fileError; - if (!error) { - error = &fileError; + return; } - __block BOOL success = YES; - void(^storeImageDataBlock)(void) = ^{ - success = [self _storeImageDataToDisk:imageData forKey:key error:error]; - }; - dispatch_sync(self.ioQueue, storeImageDataBlock); - - return success; + dispatch_sync(self.ioQueue, ^{ + [self _storeImageDataToDisk:imageData forKey:key]; + }); } // Make sure to call form io queue by caller -- (BOOL)_storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key error:(NSError * _Nullable __autoreleasing * _Nonnull)error { +- (void)_storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key { if (!imageData || !key) { - return NO; + return; } if (![self.fileManager fileExistsAtPath:_diskCachePath]) { - if (![self.fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:error]) { - return NO; + if (![self.fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:nil]) { + return; } } @@ -349,8 +339,8 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { // NSFileManager's `createFileAtPath:` is used just for old code compatibility and will not trigger any delegate methods, so it's useless for custom NSFileManager at all. // And also, NSFileManager's `createFileAtPath:` can only grab underlying POSIX errno, but NSData can grab errors defined in NSCocoaErrorDomain, which is better for user to check. - if (![imageData writeToURL:fileURL options:self.config.diskCacheWritingOptions error:error]) { - return NO; + if (![imageData writeToURL:fileURL options:self.config.diskCacheWritingOptions error:nil]) { + return; } // disable iCloud backup @@ -358,8 +348,6 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { // ignore iCloud backup resource value error [fileURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil]; } - - return YES; } #pragma mark - Query and Retrieve Ops @@ -452,7 +440,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } } - return nil; + return data; } - (nullable UIImage *)diskImageForKey:(nullable NSString *)key { diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index 4a53c7c2..948e3adb 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -57,8 +57,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test05ClearMemoryCache{ XCTestExpectation *expectation = [self expectationWithDescription:@"Clear memory cache"]; - [[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:^(NSError * _Nullable error) { - expect(error).to.beNil(); + [[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:^{ [[SDImageCache sharedImageCache] clearMemory]; expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.beNil; [[SDImageCache sharedImageCache] diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) { @@ -185,8 +184,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test21InitialDiskCount{ XCTestExpectation *expectation = [self expectationWithDescription:@"getDiskCount"]; - [[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:^(NSError * _Nullable error) { - expect(error).to.beNil(); + [[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:^{ expect([[SDImageCache sharedImageCache] getDiskCount]).to.equal(1); [[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{ [expectation fulfill]; @@ -207,8 +205,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test33CachePathForExistingKey{ XCTestExpectation *expectation = [self expectationWithDescription:@"cachePathForKey inPath"]; - [[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:^(NSError * _Nullable error) { - expect(error).to.beNil(); + [[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:^{ NSString *path = [[SDImageCache sharedImageCache] cachePathForKey:kImageTestKey]; expect(path).notTo.beNil; [[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{ @@ -237,7 +234,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; UIImage *image = [[UIImage alloc] initWithContentsOfFile:[self testImagePath]]; NSData *imageData = UIImageJPEGRepresentation(image, 1.0); - [[SDImageCache sharedImageCache] storeImageDataToDisk:imageData forKey:kImageTestKey error:nil]; + [[SDImageCache sharedImageCache] storeImageDataToDisk:imageData forKey:kImageTestKey]; UIImage *storedImageFromMemory = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]; expect(storedImageFromMemory).to.equal(nil); @@ -269,7 +266,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; NSString *key = @"TestPNGImageEncodedToDataAndRetrieveToJPEG"; - [cache storeImage:image imageData:nil forKey:key toDisk:YES completion:^(NSError * _Nullable error) { + [cache storeImage:image imageData:nil forKey:key toDisk:YES completion:^{ [cache clearMemory]; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" @@ -309,35 +306,19 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; } #endif -- (void)test41StoreImageDataToDiskWithError { +- (void)test41StoreImageDataToDiskWithCustomFileManager { NSData *imageData = [NSData dataWithContentsOfFile:[self testImagePath]]; NSError *targetError = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteNoPermissionError userInfo:nil]; - NSError *error = nil; + SDMockFileManager *fileManager = [[SDMockFileManager alloc] init]; fileManager.mockSelectors = @{NSStringFromSelector(@selector(createDirectoryAtPath:withIntermediateDirectories:attributes:error:)) : targetError}; - SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"test" - diskCacheDirectory:@"/" - fileManager:fileManager]; - [cache storeImageDataToDisk:imageData - forKey:kImageTestKey - error:&error]; + expect(fileManager.lastError).to.beNil(); - XCTAssertEqual(error.code, NSFileWriteNoPermissionError); -} - -- (void)test42StoreImageDataToDiskWithoutError { - NSData *imageData = [NSData dataWithContentsOfFile:[self testImagePath]]; - NSError *error = nil; - SDMockFileManager *fileManager = [[SDMockFileManager alloc] init]; - fileManager.mockSelectors = @{NSStringFromSelector(@selector(createDirectoryAtPath:withIntermediateDirectories:attributes:error:)) : [NSNull null]}; - SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"test" - diskCacheDirectory:@"/" - fileManager:fileManager]; + // This disk cache path creation will be mocked with error. + SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"test" diskCacheDirectory:@"/" fileManager:fileManager]; [cache storeImageDataToDisk:imageData - forKey:kImageTestKey - error:&error]; - - XCTAssertNil(error); + forKey:kImageTestKey]; + expect(fileManager.lastError).equal(targetError); } #pragma mark Helper methods diff --git a/Tests/Tests/SDMockFileManager.h b/Tests/Tests/SDMockFileManager.h index d93d1ac4..71f2aceb 100644 --- a/Tests/Tests/SDMockFileManager.h +++ b/Tests/Tests/SDMockFileManager.h @@ -11,6 +11,8 @@ // This is a mock class to provide custom error for methods @interface SDMockFileManager : NSFileManager +@property (nonatomic, strong, readonly, nullable) NSError *lastError; + @property (nonatomic, copy, nullable) NSDictionary *mockSelectors; // used to specify mocked selectors which will return NO with specify error instead of normal process. If you specify a NSNull, will use nil instead. @end diff --git a/Tests/Tests/SDMockFileManager.m b/Tests/Tests/SDMockFileManager.m index 472797fb..bf8cda58 100644 --- a/Tests/Tests/SDMockFileManager.m +++ b/Tests/Tests/SDMockFileManager.m @@ -10,11 +10,14 @@ @interface SDMockFileManager () +@property (nonatomic, strong, nullable) NSError *lastError; + @end @implementation SDMockFileManager - (BOOL)createDirectoryAtPath:(NSString *)path withIntermediateDirectories:(BOOL)createIntermediates attributes:(NSDictionary *)attributes error:(NSError * _Nullable __autoreleasing *)error { + self.lastError = nil; NSError *mockError = [self.mockSelectors objectForKey:NSStringFromSelector(_cmd)]; if ([mockError isEqual:[NSNull null]]) { if (error) { @@ -25,6 +28,7 @@ if (error) { *error = mockError; } + self.lastError = mockError; return NO; } else { return [super createDirectoryAtPath:path withIntermediateDirectories:createIntermediates attributes:attributes error:error]; From 7272cf78e574ee20f1d99a0c76de4c0e13b99449 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 14 Apr 2018 16:59:34 +0800 Subject: [PATCH 118/361] Fix the silly mistake that view category internal completion block call swapped cacheType and finished arg --- SDWebImage/UIView+WebCache.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index a651b9ec..59666b6b 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -179,7 +179,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; dispatch_main_async_safe(^{ if (completedBlock) { NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; - completedBlock(nil, nil, error, YES, SDImageCacheTypeNone, url); + completedBlock(nil, nil, error, SDImageCacheTypeNone, YES, url); } }); } From 3d7896f663f60beacc6b76983305de34fadd752a Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 14 Apr 2018 18:18:45 +0800 Subject: [PATCH 119/361] Adopt the current cache key filter and cache serializer to support using in context options. Using a protocol based object store block instead block itself. --- SDWebImage.xcodeproj/project.pbxproj | 98 +++++++++++++++++-- SDWebImage/SDWebImageCacheKeyFilter.h | 26 +++++ SDWebImage/SDWebImageCacheKeyFilter.m | 39 ++++++++ SDWebImage/SDWebImageCacheSerializer.h | 26 +++++ SDWebImage/SDWebImageCacheSerializer.m | 39 ++++++++ SDWebImage/SDWebImageDefine.h | 10 ++ SDWebImage/SDWebImageDefine.m | 2 + .../SDWebImageDownloaderRequestModifier.h | 1 + SDWebImage/SDWebImageManager.h | 25 ++--- SDWebImage/SDWebImageManager.m | 34 +++++-- WebImage/SDWebImage.h | 2 + 11 files changed, 270 insertions(+), 32 deletions(-) create mode 100644 SDWebImage/SDWebImageCacheKeyFilter.h create mode 100644 SDWebImage/SDWebImageCacheKeyFilter.m create mode 100644 SDWebImage/SDWebImageCacheSerializer.h create mode 100644 SDWebImage/SDWebImageCacheSerializer.m diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index a718aecd..2c1c925f 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -388,6 +388,30 @@ 327054DD206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; 327054DE206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; 327054DF206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; + 328BB69C2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB69D2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB69E2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB69F2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6A02081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6A12081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6A22081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */; }; + 328BB6A32081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */; }; + 328BB6A42081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */; }; + 328BB6A52081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */; }; + 328BB6A62081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */; }; + 328BB6A72081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */; }; + 328BB6AA2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6AB2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6AC2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6AD2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6AE2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6AF2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6B02081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6A92081FEE500760D6C /* SDWebImageCacheSerializer.m */; }; + 328BB6B12081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6A92081FEE500760D6C /* SDWebImageCacheSerializer.m */; }; + 328BB6B22081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6A92081FEE500760D6C /* SDWebImageCacheSerializer.m */; }; + 328BB6B32081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6A92081FEE500760D6C /* SDWebImageCacheSerializer.m */; }; + 328BB6B42081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6A92081FEE500760D6C /* SDWebImageCacheSerializer.m */; }; + 328BB6B52081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6A92081FEE500760D6C /* SDWebImageCacheSerializer.m */; }; 3290FA041FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3290FA051FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3290FA061FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1492,6 +1516,10 @@ 325312C7200F09910046BF1E /* SDWebImageTransition.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransition.m; sourceTree = ""; }; 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageAPNGCoder.h; sourceTree = ""; }; 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageAPNGCoder.m; sourceTree = ""; }; + 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCacheKeyFilter.h; sourceTree = ""; }; + 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCacheKeyFilter.m; sourceTree = ""; }; + 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCacheSerializer.h; sourceTree = ""; }; + 328BB6A92081FEE500760D6C /* SDWebImageCacheSerializer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCacheSerializer.m; sourceTree = ""; }; 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageFrame.h; sourceTree = ""; }; 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageFrame.m; sourceTree = ""; }; 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImage+WebCache.h"; path = "SDWebImage/UIImage+WebCache.h"; sourceTree = ""; }; @@ -1824,6 +1852,37 @@ name = ImageView; sourceTree = ""; }; + 328BB6972081FDAB00760D6C /* Manager */ = { + isa = PBXGroup; + children = ( + 53922D8E148C56230056699D /* SDWebImageManager.h */, + 53922D8F148C56230056699D /* SDWebImageManager.m */, + 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */, + 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */, + 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */, + 328BB6A92081FEE500760D6C /* SDWebImageCacheSerializer.m */, + ); + name = Manager; + sourceTree = ""; + }; + 328BB6982081FDD800760D6C /* Prefetcher */ = { + isa = PBXGroup; + children = ( + 53922D91148C56230056699D /* SDWebImagePrefetcher.h */, + 53922D92148C56230056699D /* SDWebImagePrefetcher.m */, + ); + name = Prefetcher; + sourceTree = ""; + }; + 328BB6992081FDDF00760D6C /* Transformer */ = { + isa = PBXGroup; + children = ( + 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */, + 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */, + ); + name = Transformer; + sourceTree = ""; + }; 4369C2851D9811BB007E863A /* WebCache Categories */ = { isa = PBXGroup; children = ( @@ -1940,12 +1999,12 @@ 53922D74148C55820056699D /* SDWebImage */ = { isa = PBXGroup; children = ( - 53922D88148C56230056699D /* SDWebImageCompat.h */, - 5340674F167780C40042B59E /* SDWebImageCompat.m */, - 530E49E71646388E002868E7 /* SDWebImageOperation.h */, + 328BB6972081FDAB00760D6C /* Manager */, 53922DAB148C56810056699D /* Downloader */, 53922DAA148C56470056699D /* Cache */, 321E60831F38E88F00405457 /* Decoder */, + 328BB6982081FDD800760D6C /* Prefetcher */, + 328BB6992081FDDF00760D6C /* Transformer */, 32484756201775CE00AF9E5A /* ImageView */, 53922DAC148C56DD0056699D /* Utils */, 53922DA9148C562D0056699D /* Categories */, @@ -2007,18 +2066,15 @@ 53922DAC148C56DD0056699D /* Utils */ = { isa = PBXGroup; children = ( - 53922D8E148C56230056699D /* SDWebImageManager.h */, - 53922D8F148C56230056699D /* SDWebImageManager.m */, - 53922D91148C56230056699D /* SDWebImagePrefetcher.h */, - 53922D92148C56230056699D /* SDWebImagePrefetcher.m */, + 53922D88148C56230056699D /* SDWebImageCompat.h */, + 5340674F167780C40042B59E /* SDWebImageCompat.m */, + 530E49E71646388E002868E7 /* SDWebImageOperation.h */, 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */, 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */, 325312C6200F09910046BF1E /* SDWebImageTransition.h */, 325312C7200F09910046BF1E /* SDWebImageTransition.m */, 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */, 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */, - 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */, - 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */, ); name = Utils; sourceTree = ""; @@ -2207,6 +2263,7 @@ 4317395A1CDFC8B70008FEB9 /* mux_types.h in Headers */, 431739561CDFC8B70008FEB9 /* demux.h in Headers */, 32B9B53A206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, + 328BB6AD2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 80377C4A1F2F666300F89830 /* bit_writer_utils.h in Headers */, 4397D2F81D0DF44200BB2784 /* MKAnnotationView+WebCache.h in Headers */, 323F8BE71F38EF770092B609 /* vp8li_enc.h in Headers */, @@ -2284,6 +2341,7 @@ 80377C551F2F666300F89830 /* quant_levels_dec_utils.h in Headers */, 80377EC11F2F66D500F89830 /* vp8_dec.h in Headers */, 00733A651BC4880E00A5A117 /* SDWebImageDownloader.h in Headers */, + 328BB69F2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2298,6 +2356,7 @@ 321E60B11F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 80377E9A1F2F66D400F89830 /* common_dec.h in Headers */, 327054D5206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, + 328BB6AB2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 32B9B538206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 80377C231F2F666300F89830 /* quant_levels_utils.h in Headers */, 321E60BF1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, @@ -2305,6 +2364,7 @@ 807A12291F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, 32F7C0852030719600873181 /* UIImage+Transform.h in Headers */, 80377C141F2F666300F89830 /* bit_reader_utils.h in Headers */, + 328BB69D2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, 323F8C0F1F38EF770092B609 /* muxi.h in Headers */, 32F7C0702030114C00873181 /* SDWebImageTransformer.h in Headers */, 80377C2B1F2F666300F89830 /* utils.h in Headers */, @@ -2379,6 +2439,7 @@ buildActionMask = 2147483647; files = ( 80377C791F2F666400F89830 /* utils.h in Headers */, + 328BB6A02081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, 323F8B721F38EF770092B609 /* delta_palettization_enc.h in Headers */, 32CF1C0B1FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, 431BB6D71D06D2C1006A3455 /* UIImage+WebP.h in Headers */, @@ -2424,6 +2485,7 @@ 431BB6EE1D06D2C1006A3455 /* NSData+ImageContentType.h in Headers */, 431BB6EF1D06D2C1006A3455 /* SDWebImagePrefetcher.h in Headers */, 80377C671F2F666400F89830 /* endian_inl_utils.h in Headers */, + 328BB6AE2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 80377C6B1F2F666400F89830 /* huffman_encode_utils.h in Headers */, 323F8C121F38EF770092B609 /* muxi.h in Headers */, 32C0FDE52013426C001B8F2D /* SDWebImageIndicator.h in Headers */, @@ -2474,6 +2536,7 @@ 80377EDA1F2F66D500F89830 /* common_dec.h in Headers */, 80377EE61F2F66D500F89830 /* webpi_dec.h in Headers */, 32B9B53C206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, + 328BB6AF2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 4397D2BA1D0DDD8C00BB2784 /* demux.h in Headers */, 80377C8F1F2F666400F89830 /* rescaler_utils.h in Headers */, 4397D2BD1D0DDD8C00BB2784 /* types.h in Headers */, @@ -2551,6 +2614,7 @@ 4397D2ED1D0DDD8C00BB2784 /* mux_types.h in Headers */, 80377C831F2F666400F89830 /* filters_utils.h in Headers */, 80377E651F2F66A800F89830 /* msa_macro.h in Headers */, + 328BB6A12081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2566,6 +2630,7 @@ 4317394F1CDFC8B70008FEB9 /* demux.h in Headers */, 43CE757D1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, + 328BB6AC2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 80377C301F2F666300F89830 /* bit_writer_utils.h in Headers */, 431739541CDFC8B70008FEB9 /* types.h in Headers */, 323F8BE61F38EF770092B609 /* vp8li_enc.h in Headers */, @@ -2643,6 +2708,7 @@ 80377EB11F2F66D400F89830 /* vp8_dec.h in Headers */, 4A2CAE291AB4BB7500B6BC39 /* NSData+ImageContentType.h in Headers */, 431739531CDFC8B70008FEB9 /* mux_types.h in Headers */, + 328BB69E2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2683,6 +2749,7 @@ 329A18591FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 5376131A155AD0D5005750A4 /* SDWebImageDownloader.h in Headers */, 4369C2771D9807EC007E863A /* UIView+WebCache.h in Headers */, + 328BB6AA2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 80377CEF1F2F66A100F89830 /* dsp.h in Headers */, 32F21B5120788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 80377C011F2F665300F89830 /* filters_utils.h in Headers */, @@ -2700,6 +2767,7 @@ 5376131F155AD0D5005750A4 /* UIButton+WebCache.h in Headers */, 327054D4206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, 53761320155AD0D5005750A4 /* UIImageView+WebCache.h in Headers */, + 328BB69C2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, 530E49E816464C25002868E7 /* SDWebImageOperation.h in Headers */, 32484769201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 80377E961F2F66D000F89830 /* webpi_dec.h in Headers */, @@ -2969,6 +3037,7 @@ 323F8BE11F38EF770092B609 /* vp8l_enc.c in Sources */, 80377DAB1F2F66A700F89830 /* alpha_processing_sse41.c in Sources */, 80377DBA1F2F66A700F89830 /* dec_neon.c in Sources */, + 328BB6A52081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 80377C5C1F2F666300F89830 /* thread_utils.c in Sources */, 00733A5A1BC4880000A5A117 /* SDWebImagePrefetcher.m in Sources */, 80377DBF1F2F66A700F89830 /* enc_avx2.c in Sources */, @@ -3105,6 +3174,7 @@ 80377DE21F2F66A700F89830 /* rescaler.c in Sources */, 329A18621FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, 80377DAD1F2F66A700F89830 /* argb_mips_dsp_r2.c in Sources */, + 328BB6B32081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, 00733A601BC4880000A5A117 /* UIImageView+HighlightedWebCache.m in Sources */, 323F8BAB1F38EF770092B609 /* picture_psnr_enc.c in Sources */, 323F8BA51F38EF770092B609 /* picture_enc.c in Sources */, @@ -3188,6 +3258,7 @@ 80377D5F1F2F66A700F89830 /* yuv_mips32.c in Sources */, 80377D3C1F2F66A700F89830 /* enc.c in Sources */, 4314D13B1D0E0E3B004B36C9 /* UIButton+WebCache.m in Sources */, + 328BB6A32081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 32F21B5820788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 321E60C51F38E91700405457 /* UIImage+ForceDecode.m in Sources */, 80377D461F2F66A700F89830 /* lossless_enc_neon.c in Sources */, @@ -3238,6 +3309,7 @@ 80377C1A1F2F666300F89830 /* filters_utils.c in Sources */, 323F8B9D1F38EF770092B609 /* picture_csp_enc.c in Sources */, 4314D14B1D0E0E3B004B36C9 /* SDWebImageCompat.m in Sources */, + 328BB6B12081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, 4314D14D1D0E0E3B004B36C9 /* UIImage+GIF.m in Sources */, 32CF1C0E1FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */, 323F8B571F38EF770092B609 /* config_enc.c in Sources */, @@ -3345,6 +3417,7 @@ 80377E2E1F2F66A800F89830 /* yuv_mips32.c in Sources */, 80377E0B1F2F66A800F89830 /* enc.c in Sources */, 431BB6AC1D06D2C1006A3455 /* SDWebImageCompat.m in Sources */, + 328BB6A62081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 32F21B5B20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 80377E151F2F66A800F89830 /* lossless_enc_neon.c in Sources */, 321E60C81F38E91700405457 /* UIImage+ForceDecode.m in Sources */, @@ -3395,6 +3468,7 @@ 80377E141F2F66A800F89830 /* lossless_enc_msa.c in Sources */, 323F8BA01F38EF770092B609 /* picture_csp_enc.c in Sources */, 80377C701F2F666400F89830 /* quant_levels_utils.c in Sources */, + 328BB6B42081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, 431BB6BD1D06D2C1006A3455 /* UIImage+GIF.m in Sources */, 32CF1C111FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */, 323F8B5A1F38EF770092B609 /* config_enc.c in Sources */, @@ -3477,6 +3551,7 @@ 80377E6C1F2F66A800F89830 /* rescaler.c in Sources */, 32484762201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 80377EE31F2F66D500F89830 /* vp8l_dec.c in Sources */, + 328BB6B52081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, 80377ED71F2F66D500F89830 /* alpha_dec.c in Sources */, 323F8B7F1F38EF770092B609 /* frame_enc.c in Sources */, 80377E681F2F66A800F89830 /* rescaler_mips32.c in Sources */, @@ -3504,6 +3579,7 @@ 80377E3B1F2F66A800F89830 /* cost_mips_dsp_r2.c in Sources */, 4397D29B1D0DDD8C00BB2784 /* SDWebImageDownloader.m in Sources */, 80377E711F2F66A800F89830 /* upsampling.c in Sources */, + 328BB6A72081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 4397D29C1D0DDD8C00BB2784 /* NSData+ImageContentType.m in Sources */, 323F8BB31F38EF770092B609 /* picture_rescale_enc.c in Sources */, 80377E6A1F2F66A800F89830 /* rescaler_neon.c in Sources */, @@ -3603,6 +3679,7 @@ 323F8BE01F38EF770092B609 /* vp8l_enc.c in Sources */, 80377D751F2F66A700F89830 /* dec_neon.c in Sources */, 80377C421F2F666300F89830 /* thread_utils.c in Sources */, + 328BB6A42081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 4A2CAE2E1AB4BB7500B6BC39 /* UIImage+GIF.m in Sources */, 80377D7A1F2F66A700F89830 /* enc_avx2.c in Sources */, 80377D821F2F66A700F89830 /* filters_mips_dsp_r2.c in Sources */, @@ -3739,6 +3816,7 @@ 80377D8B1F2F66A700F89830 /* lossless_enc_neon.c in Sources */, 329A18611FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, 80377D9D1F2F66A700F89830 /* rescaler.c in Sources */, + 328BB6B22081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, 80377D681F2F66A700F89830 /* argb_mips_dsp_r2.c in Sources */, 323F8BAA1F38EF770092B609 /* picture_psnr_enc.c in Sources */, 323F8BA41F38EF770092B609 /* picture_enc.c in Sources */, @@ -3764,6 +3842,7 @@ 323F8BDE1F38EF770092B609 /* vp8l_enc.c in Sources */, 80377CEB1F2F66A100F89830 /* dec_neon.c in Sources */, 80377C0E1F2F665300F89830 /* thread_utils.c in Sources */, + 328BB6A22081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, 53761309155AD0D5005750A4 /* SDImageCache.m in Sources */, 80377CF01F2F66A100F89830 /* enc_avx2.c in Sources */, 80377CF81F2F66A100F89830 /* filters_mips_dsp_r2.c in Sources */, @@ -3900,6 +3979,7 @@ 80377D011F2F66A100F89830 /* lossless_enc_neon.c in Sources */, 329A185F1FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, 80377D131F2F66A100F89830 /* rescaler.c in Sources */, + 328BB6B02081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, 80377CDE1F2F66A100F89830 /* argb_mips_dsp_r2.c in Sources */, 323F8BA81F38EF770092B609 /* picture_psnr_enc.c in Sources */, 323F8BA21F38EF770092B609 /* picture_enc.c in Sources */, diff --git a/SDWebImage/SDWebImageCacheKeyFilter.h b/SDWebImage/SDWebImageCacheKeyFilter.h new file mode 100644 index 00000000..05dde712 --- /dev/null +++ b/SDWebImage/SDWebImageCacheKeyFilter.h @@ -0,0 +1,26 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" + +typedef NSString * _Nullable(^SDWebImageCacheKeyFilterBlock)(NSURL * _Nonnull url); + +// This is the protocol for cache key filter. We can use a block to specify the cache key filter. But Using protocol can make this extensible, and allow Swift user to use it easily instead of using `@convention(block)` to store a block into context options. +@protocol SDWebImageCacheKeyFilter + +- (nullable NSString *)cacheKeyForURL:(nonnull NSURL *)url; + +@end + +@interface SDWebImageCacheKeyFilter : NSObject + +- (nonnull instancetype)initWithBlock:(nonnull SDWebImageCacheKeyFilterBlock)block; ++ (nonnull instancetype)cacheKeyFilterWithBlock:(nonnull SDWebImageCacheKeyFilterBlock)block; + +@end diff --git a/SDWebImage/SDWebImageCacheKeyFilter.m b/SDWebImage/SDWebImageCacheKeyFilter.m new file mode 100644 index 00000000..b4ebb8b4 --- /dev/null +++ b/SDWebImage/SDWebImageCacheKeyFilter.m @@ -0,0 +1,39 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCacheKeyFilter.h" + +@interface SDWebImageCacheKeyFilter () + +@property (nonatomic, copy, nonnull) SDWebImageCacheKeyFilterBlock block; + +@end + +@implementation SDWebImageCacheKeyFilter + +- (instancetype)initWithBlock:(SDWebImageCacheKeyFilterBlock)block { + self = [super init]; + if (self) { + self.block = block; + } + return self; +} + ++ (instancetype)cacheKeyFilterWithBlock:(SDWebImageCacheKeyFilterBlock)block { + SDWebImageCacheKeyFilter *cacheKeyFilter = [[SDWebImageCacheKeyFilter alloc] initWithBlock:block]; + return cacheKeyFilter; +} + +- (NSString *)cacheKeyForURL:(NSURL *)url { + if (!self.block) { + return nil; + } + return self.block(url); +} + +@end diff --git a/SDWebImage/SDWebImageCacheSerializer.h b/SDWebImage/SDWebImageCacheSerializer.h new file mode 100644 index 00000000..1a6c1698 --- /dev/null +++ b/SDWebImage/SDWebImageCacheSerializer.h @@ -0,0 +1,26 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" + +typedef NSData * _Nullable(^SDWebImageCacheSerializerBlock)(UIImage * _Nonnull image, NSData * _Nullable data, NSURL * _Nullable imageURL); + +// This is the protocol for cache serializer. We can use a block to specify the cache serializer. But Using protocol can make this extensible, and allow Swift user to use it easily instead of using `@convention(block)` to store a block into context options. +@protocol SDWebImageCacheSerializer + +- (nullable NSData *)cacheDataWithImage:(nonnull UIImage *)image originalData:(nullable NSData *)data imageURL:(nullable NSURL *)imageURL; + +@end + +@interface SDWebImageCacheSerializer : NSObject + +- (nonnull instancetype)initWithBlock:(nonnull SDWebImageCacheSerializerBlock)block; ++ (nonnull instancetype)cacheSerializerWithBlock:(nonnull SDWebImageCacheSerializerBlock)block; + +@end diff --git a/SDWebImage/SDWebImageCacheSerializer.m b/SDWebImage/SDWebImageCacheSerializer.m new file mode 100644 index 00000000..51528e68 --- /dev/null +++ b/SDWebImage/SDWebImageCacheSerializer.m @@ -0,0 +1,39 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCacheSerializer.h" + +@interface SDWebImageCacheSerializer () + +@property (nonatomic, copy, nonnull) SDWebImageCacheSerializerBlock block; + +@end + +@implementation SDWebImageCacheSerializer + +- (instancetype)initWithBlock:(SDWebImageCacheSerializerBlock)block { + self = [super init]; + if (self) { + self.block = block; + } + return self; +} + ++ (instancetype)cacheSerializerWithBlock:(SDWebImageCacheSerializerBlock)block { + SDWebImageCacheSerializer *cacheSerializer = [[SDWebImageCacheSerializer alloc] initWithBlock:block]; + return cacheSerializer; +} + +- (NSData *)cacheDataWithImage:(UIImage *)image originalData:(NSData *)data imageURL:(nullable NSURL *)imageURL { + if (!self.block) { + return nil; + } + return self.block(image, data, imageURL); +} + +@end diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index cf4eb3d3..d0421964 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -204,3 +204,13 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextAnimat A id instance to modify the image download request. It's used for downloader to modify the original request from URL and options. If you provide one, it will ignore the `requestModifier` in downloader and use provided one instead. (id) */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextDownloadRequestModifier; + +/** + A id instance to convert an URL into a cache key. It's used when manager need cache key to use image cache. If you provide one, it will ignore the `cacheKeyFilter` in manager and use provided one instead. (id) + */ +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCacheKeyFilter; + +/** + A id instance to convert the decoded image, the source downloaded data, to the actual data. It's used for manager to store image to the disk cache. If you provide one, it will ignore the `cacheSerializer` in manager and use provided one instead. (id) + */ +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCacheSerializer; diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m index d86a3004..6b843ac0 100644 --- a/SDWebImage/SDWebImageDefine.m +++ b/SDWebImage/SDWebImageDefine.m @@ -123,3 +123,5 @@ SDWebImageContextOption const SDWebImageContextCustomTransformer = @"customTrans SDWebImageContextOption const SDWebImageContextImageScaleFactor = @"imageScaleFactor"; SDWebImageContextOption const SDWebImageContextAnimatedImageClass = @"animatedImageClass"; SDWebImageContextOption const SDWebImageContextDownloadRequestModifier = @"downloadRequestModifier"; +SDWebImageContextOption const SDWebImageContextCacheKeyFilter = @"cacheKeyFilter"; +SDWebImageContextOption const SDWebImageContextCacheSerializer = @"cacheSerializer"; diff --git a/SDWebImage/SDWebImageDownloaderRequestModifier.h b/SDWebImage/SDWebImageDownloaderRequestModifier.h index 1c31db92..fc449059 100644 --- a/SDWebImage/SDWebImageDownloaderRequestModifier.h +++ b/SDWebImage/SDWebImageDownloaderRequestModifier.h @@ -11,6 +11,7 @@ typedef NSURLRequest * _Nullable (^SDWebImageDownloaderRequestModifierBlock)(NSURLRequest * _Nonnull request); +// This is the protocol for downloader request modifier. We can use a block to specify the downloader request modifier. But Using protocol can make this extensible, and allow Swift user to use it easily instead of using `@convention(block)` to store a block into context options. @protocol SDWebImageDownloaderRequestModifier - (nullable NSURLRequest *)modifiedRequestWithRequest:(nonnull NSURLRequest *)request; diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index e93353bb..b1724058 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -11,15 +11,13 @@ #import "SDWebImageDownloader.h" #import "SDImageCache.h" #import "SDWebImageTransformer.h" +#import "SDWebImageCacheKeyFilter.h" +#import "SDWebImageCacheSerializer.h" typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL); typedef void(^SDInternalCompletionBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL); -typedef NSString * _Nullable(^SDWebImageCacheKeyFilterBlock)(NSURL * _Nullable url); - -typedef NSData * _Nullable(^SDWebImageCacheSerializerBlock)(UIImage * _Nonnull image, NSData * _Nullable data, NSURL * _Nullable imageURL); - // A combined operation representing the cache and download operation. You can it to cancel the load process. @interface SDWebImageCombinedOperation : NSObject @@ -117,30 +115,27 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; @property (strong, nonatomic, nullable) id transformer; /** - * The cache filter is a block used each time SDWebImageManager need to convert an URL into a cache key. This can - * be used to remove dynamic part of an image URL. + * The cache filter is used to convert an URL into a cache key each time SDWebImageManager need cache key to use image cache. * * The following example sets a filter in the application delegate that will remove any query-string from the * URL before to use it as a cache key: * * @code - -SDWebImageManager.sharedManager.cacheKeyFilter = ^(NSURL * _Nullable url) { + SDWebImageManager.sharedManager.cacheKeyFilter =[SDWebImageCacheKeyFilter cacheKeyFilterWithBlock:^NSString * _Nullable(NSURL * _Nonnull url) { url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path]; return [url absoluteString]; -}; - + }]; * @endcode */ -@property (nonatomic, copy, nullable) SDWebImageCacheKeyFilterBlock cacheKeyFilter; +@property (nonatomic, strong, nullable) id cacheKeyFilter; /** - * The cache serializer is a block used to convert the decoded image, the source downloaded data, to the actual data used for storing to the disk cache. If you return nil, means to generate the data from the image instance, see `SDImageCache`. + * The cache serializer is used to convert the decoded image, the source downloaded data, to the actual data used for storing to the disk cache. If you return nil, means to generate the data from the image instance, see `SDImageCache`. * For example, if you are using WebP images and facing the slow decoding time issue when later retriving from disk cache again. You can try to encode the decoded image to JPEG/PNG format to disk cache instead of source downloaded data. * @note The `image` arg is nonnull, but when you also provide a image transformer and the image is transformed, the `data` arg may be nil, take attention to this case. * @note This method is called from a global queue in order to not to block the main thread. * @code - SDWebImageManager.sharedManager.cacheSerializer = ^NSData * _Nullable(UIImage * _Nonnull image, NSData * _Nullable data, NSURL * _Nullable imageURL) { + SDWebImageManager.sharedManager.cacheSerializer = [SDWebImageCacheSerializer cacheSerializerWithBlock:^NSData * _Nullable(UIImage * _Nonnull image, NSData * _Nullable data, NSURL * _Nullable imageURL) { SDImageFormat format = [NSData sd_imageFormatForImageData:data]; switch (format) { case SDImageFormatWebP: @@ -148,11 +143,11 @@ SDWebImageManager.sharedManager.cacheKeyFilter = ^(NSURL * _Nullable url) { default: return data; } - }; +}]; * @endcode * The default value is nil. Means we just store the source downloaded data to disk cache. */ -@property (nonatomic, copy, nullable) SDWebImageCacheSerializerBlock cacheSerializer; +@property (nonatomic, strong, nullable) id cacheSerializer; /** * Check one or more operations running diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 1400a249..bf9cc0e5 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -57,12 +57,16 @@ } - (nullable NSString *)cacheKeyForURL:(nullable NSURL *)url { + return [self cacheKeyForURL:url cacheKeyFilter:self.cacheKeyFilter]; +} + +- (nullable NSString *)cacheKeyForURL:(nullable NSURL *)url cacheKeyFilter:(id)cacheKeyFilter { if (!url) { return @""; } - if (self.cacheKeyFilter) { - return self.cacheKeyFilter(url); + if (cacheKeyFilter) { + return [cacheKeyFilter cacheKeyForURL:url]; } else { return url.absoluteString; } @@ -149,7 +153,6 @@ @synchronized (self.runningOperations) { [self.runningOperations addObject:operation]; } - NSString *key = [self cacheKeyForURL:url]; SDImageCacheOptions cacheOptions = 0; if (options & SDWebImageQueryDataWhenInMemory) cacheOptions |= SDImageCacheQueryDataWhenInMemory; @@ -174,6 +177,21 @@ [mutableContext setValue:transformer forKey:SDWebImageContextCustomTransformer]; context = [mutableContext copy]; } + // Cache key filter + id cacheKeyFilter; + if ([context valueForKey:SDWebImageContextCacheKeyFilter]) { + cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter]; + } else { + cacheKeyFilter = self.cacheKeyFilter; + } + NSString *key = [self cacheKeyForURL:url cacheKeyFilter:cacheKeyFilter]; + // Cache serializer + id cacheSerializer; + if ([context valueForKey:SDWebImageContextCacheSerializer]) { + cacheSerializer = [context valueForKey:SDWebImageContextCacheSerializer]; + } else { + cacheSerializer = self.cacheSerializer; + } __weak SDWebImageCombinedOperation *weakOperation = operation; operation.cacheOperation = [self.imageCache queryCacheOperationForKey:key options:cacheOptions context:context done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) { @@ -255,7 +273,7 @@ BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly); // We've done the scale process in SDWebImageDownloader with the shared manager, this is used for custom manager and avoid extra scale. - if (self != [SDWebImageManager sharedManager] && self.cacheKeyFilter && downloadedImage && ![downloadedImage conformsToProtocol:@protocol(SDAnimatedImage)]) { + if (self != [SDWebImageManager sharedManager] && cacheKeyFilter && downloadedImage && ![downloadedImage conformsToProtocol:@protocol(SDAnimatedImage)]) { downloadedImage = [self scaledImageForKey:key image:downloadedImage]; } @@ -270,8 +288,8 @@ BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage]; NSData *cacheData; // pass nil if the image was transformed, so we can recalculate the data from the image - if (self.cacheSerializer) { - cacheData = self.cacheSerializer(transformedImage, (imageWasTransformed ? nil : downloadedData), url); + if (cacheSerializer) { + cacheData = [cacheSerializer cacheDataWithImage:transformedImage originalData:(imageWasTransformed ? nil : downloadedData) imageURL:url]; } else { cacheData = (imageWasTransformed ? nil : downloadedData); } @@ -282,9 +300,9 @@ }); } else { if (downloadedImage && finished) { - if (self.cacheSerializer) { + if (cacheSerializer) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - NSData *cacheData = self.cacheSerializer(downloadedImage, downloadedData, url); + NSData *cacheData = [cacheSerializer cacheDataWithImage:downloadedImage originalData:downloadedData imageURL:url]; [self.imageCache storeImage:downloadedImage imageData:cacheData forKey:key toDisk:cacheOnDisk completion:nil]; }); } else { diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index 087c9ca2..5b8c0a22 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -22,6 +22,8 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import #import +#import +#import #import #import #import From fcfca57463ced0c9ba5c06a6f23ffabeb205f43e Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 14 Apr 2018 22:33:19 +0800 Subject: [PATCH 120/361] Add limitBytes arg for UIImage+ForceDecode category --- SDWebImage/UIImage+ForceDecode.h | 9 +++++++++ SDWebImage/UIImage+ForceDecode.m | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/SDWebImage/UIImage+ForceDecode.h b/SDWebImage/UIImage+ForceDecode.h index 0911a54c..25910abe 100644 --- a/SDWebImage/UIImage+ForceDecode.h +++ b/SDWebImage/UIImage+ForceDecode.h @@ -31,4 +31,13 @@ */ + (nullable UIImage *)sd_decodedAndScaledDownImageWithImage:(nullable UIImage *)image; +/** + Decompress and scale down the provided image and limit bytes + + @param image The image to be decompressed + @param bytes The limit bytes size. Provide 0 to use the build-in limit. + @return The decompressed and scaled down image + */ ++ (nullable UIImage *)sd_decodedAndScaledDownImageWithImage:(nullable UIImage *)image limitBytes:(NSUInteger)bytes; + @end diff --git a/SDWebImage/UIImage+ForceDecode.m b/SDWebImage/UIImage+ForceDecode.m index 3ddd2078..dab75162 100644 --- a/SDWebImage/UIImage+ForceDecode.m +++ b/SDWebImage/UIImage+ForceDecode.m @@ -29,10 +29,14 @@ } + (UIImage *)sd_decodedAndScaledDownImageWithImage:(UIImage *)image { + return [self sd_decodedAndScaledDownImageWithImage:image limitBytes:0]; +} + ++ (UIImage *)sd_decodedAndScaledDownImageWithImage:(UIImage *)image limitBytes:(NSUInteger)bytes { if (!image) { return nil; } - return [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; + return [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:bytes]; } @end From 94b67bf3b09cc4a68b82be6973393a21986f3e88 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 15 Apr 2018 01:36:10 +0800 Subject: [PATCH 121/361] Fix the NSSecureCoding implementation for SDAnimatedImage --- SDWebImage/SDAnimatedImage.h | 3 +- SDWebImage/SDAnimatedImage.m | 54 ++++++++++++++++++++++++++---------- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h index 00f2fb7f..a98bd302 100644 --- a/SDWebImage/SDAnimatedImage.h +++ b/SDWebImage/SDAnimatedImage.h @@ -69,7 +69,8 @@ @property (nonatomic, assign, readonly) SDImageFormat animatedImageFormat; /** - Current animated image data, you can use this instead of CGImage to create another instance + Current animated image data, you can use this instead of CGImage to create another instance. + If the current image is not animated image, this value is nil. */ @property (nonatomic, copy, readonly, nullable) NSData *animatedImageData; diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index 74e16784..30eedbb4 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -350,24 +350,50 @@ static NSArray *SDBundlePreferredScales() { #pragma mark - NSSecureCoding - (instancetype)initWithCoder:(NSCoder *)aDecoder { - NSNumber *scale = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(scale))]; - NSData *animatedImageData = [aDecoder decodeObjectOfClass:[NSData class] forKey:NSStringFromSelector(@selector(animatedImageData))]; - if (animatedImageData) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wobjc-designated-initializers" - return [self initWithData:animatedImageData scale:scale.doubleValue]; -#pragma clang diagnostic pop - } else { - return [super initWithCoder:aDecoder]; + self = [super initWithCoder:aDecoder]; + if (self) { + NSData *animatedImageData = [aDecoder decodeObjectOfClass:[NSData class] forKey:NSStringFromSelector(@selector(animatedImageData))]; + CGFloat scale; +#if SD_MAC + NSNumber *scaleValue = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(scale))]; + scale = scaleValue.doubleValue; + if (scale < 1) { + scale = 1; + } + _scale = scale; +#else + scale = self.scale; +#endif + if (!animatedImageData) { + return self; + } + id animatedCoder = nil; + for (idcoder in [SDWebImageCodersManager sharedManager].coders) { + if ([coder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { + if ([coder canDecodeFromData:animatedImageData]) { + animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:animatedImageData options:@{SDWebImageCoderDecodeScaleFactor : @(scale)}]; + break; + } + } + } + if (!animatedCoder) { + return self; + } + _coder = animatedCoder; + SDImageFormat format = [NSData sd_imageFormatForImageData:animatedImageData]; + _animatedImageFormat = format; } + return self; } - (void)encodeWithCoder:(NSCoder *)aCoder { - if (self.animatedImageData) { - [aCoder encodeObject:self.animatedImageData forKey:NSStringFromSelector(@selector(animatedImageData))]; - [aCoder encodeObject:@(self.scale) forKey:NSStringFromSelector(@selector(scale))]; - } else { - [super encodeWithCoder:aCoder]; + [super encodeWithCoder:aCoder]; +#if SD_MAC + [aCoder encodeObject:@(self.scale) forKey:NSStringFromSelector(@selector(scale))]; +#endif + NSData *animatedImageData = self.animatedImageData; + if (animatedImageData) { + [aCoder encodeObject:animatedImageData forKey:NSStringFromSelector(@selector(animatedImageData))]; } } From d02c8d15e257db681937e4d70c1ed0eda86fd55d Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 15 Apr 2018 13:13:51 +0800 Subject: [PATCH 122/361] Use the scale category from `NSImage+Addtions` instead of manual created property for `SDAnimatedImage` on macOS --- SDWebImage/SDAnimatedImage.h | 2 +- SDWebImage/SDAnimatedImage.m | 20 +------------------- SDWebImage/SDWebImageGIFCoder.m | 2 +- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h index a98bd302..bb452669 100644 --- a/SDWebImage/SDAnimatedImage.h +++ b/SDWebImage/SDAnimatedImage.h @@ -78,7 +78,7 @@ The scale factor of the image. @note For UIKit, this just call super instead. - @note For AppKit, `NSImage` can contains multiple image representations with different scales. However, this class does not do that from the design. We processs the scale like UIKit and store it as a extra information for correctlly rendering in `SDAnimatedImageView`. + @note For AppKit, `NSImage` can contains multiple image representations with different scales. However, this class does not do that from the design. We processs the scale like UIKit. This wil actually be calculated from image size and pixel size. */ @property (nonatomic, readonly) CGFloat scale; diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index 30eedbb4..34d88051 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -205,9 +205,7 @@ static NSArray *SDBundlePreferredScales() { @end @implementation SDAnimatedImage -#if SD_UIKIT || SD_WATCH @dynamic scale; // call super -#endif #pragma mark - UIImage override method + (instancetype)imageNamed:(NSString *)name { @@ -316,9 +314,6 @@ static NSArray *SDBundlePreferredScales() { #endif if (self) { _coder = animatedCoder; -#if SD_MAC - _scale = scale; -#endif NSData *data = [animatedCoder animatedImageData]; SDImageFormat format = [NSData sd_imageFormatForImageData:data]; _animatedImageFormat = format; @@ -353,17 +348,7 @@ static NSArray *SDBundlePreferredScales() { self = [super initWithCoder:aDecoder]; if (self) { NSData *animatedImageData = [aDecoder decodeObjectOfClass:[NSData class] forKey:NSStringFromSelector(@selector(animatedImageData))]; - CGFloat scale; -#if SD_MAC - NSNumber *scaleValue = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(scale))]; - scale = scaleValue.doubleValue; - if (scale < 1) { - scale = 1; - } - _scale = scale; -#else - scale = self.scale; -#endif + CGFloat scale = self.scale; if (!animatedImageData) { return self; } @@ -388,9 +373,6 @@ static NSArray *SDBundlePreferredScales() { - (void)encodeWithCoder:(NSCoder *)aCoder { [super encodeWithCoder:aCoder]; -#if SD_MAC - [aCoder encodeObject:@(self.scale) forKey:NSStringFromSelector(@selector(scale))]; -#endif NSData *animatedImageData = self.animatedImageData; if (animatedImageData) { [aCoder encodeObject:animatedImageData forKey:NSStringFromSelector(@selector(animatedImageData))]; diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index 3db33284..c44af183 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -99,7 +99,7 @@ BOOL decodeFirstFrame = [options[SDWebImageCoderDecodeFirstFrameOnly] boolValue]; if (decodeFirstFrame || count <= 1) { - animatedImage = [[UIImage alloc] initWithData:data]; + animatedImage = [[UIImage alloc] initWithData:data scale:scale]; } else { NSMutableArray *frames = [NSMutableArray array]; From 5665b6fdf21b5cca3025b6b10b18809e3b492c90 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 15 Apr 2018 13:49:42 +0800 Subject: [PATCH 123/361] Fix the issue about scale factor using `initWithCGImage:size` macOS, we should always use `NSBitmapImageRep` to keep cross-platform compatible --- SDWebImage/NSImage+Additions.h | 2 +- SDWebImage/NSImage+Additions.m | 26 ++++++++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/SDWebImage/NSImage+Additions.h b/SDWebImage/NSImage+Additions.h index b7fdcd64..6ae7e4cf 100644 --- a/SDWebImage/NSImage+Additions.h +++ b/SDWebImage/NSImage+Additions.h @@ -27,7 +27,7 @@ The underlying Core Graphics image object. This will actually use `CGImageForPro /** Returns an image object with the scale factor and orientation. The representation is created from the Core Graphics image object. - @note The difference between this and `initWithCGImage:size` is that `initWithCGImage:size` will use `backingScaleFactor` as scale factor if you specify `NSZeroSize` and does not support orientation. + @note The difference between this and `initWithCGImage:size` is that `initWithCGImage:size` will actually create a `NSCGImageSnapshotRep` representation and always use `backingScaleFactor` as scale factor. So we should avoid it and use `NSBitmapImageRep` with `initWithCGImage:` instead. @note The difference between this and UIKit's `UIImage` equivalent method is the way to process orientation. If the provided image orientation is not equal to Up orientation, this method will firstly rotate the CGImage to the correct orientation to work compatible with `NSImageView`. However, UIKit will not actually rotate CGImage and just store it as `imageOrientation` property. @param cgImage A Core Graphics image object diff --git a/SDWebImage/NSImage+Additions.m b/SDWebImage/NSImage+Additions.m index dc68fdca..7cfb99ad 100644 --- a/SDWebImage/NSImage+Additions.m +++ b/SDWebImage/NSImage+Additions.m @@ -41,20 +41,26 @@ } - (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation { - if (scale < 1) { - scale = 1; - } - CGFloat pixelWidth = CGImageGetWidth(cgImage); - CGFloat pixelHeight = CGImageGetHeight(cgImage); - NSSize size = NSMakeSize(pixelWidth / scale, pixelHeight / scale); + NSBitmapImageRep *imageRep; if (orientation != kCGImagePropertyOrientationUp) { // AppKit design is different from UIKit. Where CGImage based image rep does not respect to any orientation. Only data based image rep which contains the EXIF metadata can automatically detect orientation. // This should be nonnull, until the memory is exhausted cause `CGBitmapContextCreate` failed. - cgImage = [SDWebImageCoderHelper CGImageCreateDecoded:cgImage orientation:orientation]; - self = [self initWithCGImage:cgImage size:size]; - CGImageRelease(cgImage); + CGImageRef rotatedCGImage = [SDWebImageCoderHelper CGImageCreateDecoded:cgImage orientation:orientation]; + imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; + CGImageRelease(rotatedCGImage); } else { - self = [self initWithCGImage:cgImage size:size]; + imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; + } + if (scale < 1) { + scale = 1; + } + CGFloat pixelWidth = imageRep.pixelsWide; + CGFloat pixelHeight = imageRep.pixelsHigh; + NSSize size = NSMakeSize(pixelWidth / scale, pixelHeight / scale); + self = [self initWithSize:size]; + if (self) { + imageRep.size = size; + [self addRepresentation:imageRep]; } return self; } From 781c079a3a0dc288a8763acb1d4b2e9559198910 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 16 Apr 2018 01:12:09 +0800 Subject: [PATCH 124/361] Use `SDWebImageAvoidDecodeImage` to allow user to control force decode feature for individual image request. Replace all the central control for `decompressImages` --- SDWebImage/SDImageCache.h | 9 +++++++-- SDWebImage/SDImageCache.m | 6 ++---- SDWebImage/SDImageCacheConfig.h | 6 ------ SDWebImage/SDImageCacheConfig.m | 1 - SDWebImage/SDWebImageDefine.h | 8 +++++++- SDWebImage/SDWebImageDownloader.h | 14 +++++++++++--- SDWebImage/SDWebImageDownloader.m | 1 - SDWebImage/SDWebImageDownloaderConfig.h | 6 ------ SDWebImage/SDWebImageDownloaderConfig.m | 2 -- SDWebImage/SDWebImageDownloaderOperation.h | 9 --------- SDWebImage/SDWebImageDownloaderOperation.m | 5 ++--- SDWebImage/UIImage+ForceDecode.h | 18 +++++++++--------- Tests/Tests/SDWebImageTestDownloadOperation.h | 1 - 13 files changed, 38 insertions(+), 48 deletions(-) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index cb5a0f0a..1adee32f 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -40,14 +40,19 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { * Use this flag to transform them anyway. */ SDImageCacheTransformAnimatedImage = 1 << 2, + /** + * By default, we will decode the image in the background during cache query and download from the network. This can help to improve performance because when rendering image on the screen, it need to be firstly decoded. But this happen on the main queue by Core Animation. + * However, this process may increase the memory usage as well. If you are experiencing a issue due to excessive memory consumption, This flag can prevent decode the image. + */ + SDImageCacheAvoidDecodeImage = 1 << 3, /** * By default, we decode the animated image. This flag can force decode the first frame only and produece the static image. */ - SDImageCacheDecodeFirstFrameOnly = 1 << 3, + SDImageCacheDecodeFirstFrameOnly = 1 << 4, /** * By default, for `SDAnimatedImage`, we decode the animated image frame during rendering to reduce memory usage. This flag actually trigger `preloadAllAnimatedImageFrames = YES` after image load from disk cache */ - SDImageCachePreloadAllFrames = 1 << 4 + SDImageCachePreloadAllFrames = 1 << 5 }; typedef void(^SDCacheQueryCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType); diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index c66e7b9b..96498460 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -473,7 +473,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (!image) { image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; } - BOOL shouldDecode = YES; + BOOL shouldDecode = (options & SDImageCacheAvoidDecodeImage) == 0; if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { // `SDAnimatedImage` do not decode shouldDecode = NO; @@ -482,9 +482,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { shouldDecode = NO; } if (shouldDecode) { - if (self.config.shouldDecompressImages) { - image = [SDWebImageCoderHelper decodedImageWithImage:image]; - } + image = [SDWebImageCoderHelper decodedImageWithImage:image]; } return image; } else { diff --git a/SDWebImage/SDImageCacheConfig.h b/SDWebImage/SDImageCacheConfig.h index 570072ae..471f64c5 100644 --- a/SDWebImage/SDImageCacheConfig.h +++ b/SDWebImage/SDImageCacheConfig.h @@ -11,12 +11,6 @@ @interface SDImageCacheConfig : NSObject -/** - * Decompressing images means pre-decoding the image that are downloaded and cached on background queue. This can avoid image view decode it on main queue when rendering. This can improve performance but can consume more memory. - * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. - */ -@property (assign, nonatomic) BOOL shouldDecompressImages; - /** * Whether or not to disable iCloud backup * Defaults to YES. diff --git a/SDWebImage/SDImageCacheConfig.m b/SDWebImage/SDImageCacheConfig.m index 923506d0..ef7f2738 100644 --- a/SDWebImage/SDImageCacheConfig.m +++ b/SDWebImage/SDImageCacheConfig.m @@ -14,7 +14,6 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week - (instancetype)init { if (self = [super init]) { - _shouldDecompressImages = YES; _shouldDisableiCloud = YES; _shouldCacheImagesInMemory = YES; _diskCacheReadingOptions = 0; diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index cf4eb3d3..4136c443 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -128,7 +128,7 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { /** * By default, images are decoded respecting their original size. On iOS, this flag will scale down the * images to a size compatible with the constrained memory of devices. - * If `SDWebImageProgressiveDownload` flag is set the scale down is deactivated. + * This flag take no effect if `SDWebImageAvoidDecodeImage` is set. And it will be ignored if `SDWebImageProgressiveDownload` is set. */ SDWebImageScaleDownLargeImages = 1 << 12, @@ -154,6 +154,12 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { */ SDWebImageForceTransition = 1 << 16, + /** + * By default, we will decode the image in the background during cache query and download from the network. This can help to improve performance because when rendering image on the screen, it need to be firstly decoded. But this happen on the main queue by Core Animation. + * However, this process may increase the memory usage as well. If you are experiencing a issue due to excessive memory consumption, This flag can prevent decode the image. + */ + SDWebImageAvoidDecodeImage = 1 << 17, + /** * By default, we decode the animated image. This flag can force decode the first frame only and produece the static image. */ diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 4cd42ea5..23bc0d66 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -60,19 +60,27 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { SDWebImageDownloaderHighPriority = 1 << 7, /** - * Scale down the image + * By default, images are decoded respecting their original size. On iOS, this flag will scale down the + * images to a size compatible with the constrained memory of devices. + * This flag take no effect if `SDWebImageDownloaderAvoidDecodeImage` is set. And it will be ignored if `SDWebImageDownloaderProgressiveDownload` is set. */ SDWebImageDownloaderScaleDownLargeImages = 1 << 8, + /** + * By default, we will decode the image in the background during cache query and download from the network. This can help to improve performance because when rendering image on the screen, it need to be firstly decoded. But this happen on the main queue by Core Animation. + * However, this process may increase the memory usage as well. If you are experiencing a issue due to excessive memory consumption, This flag can prevent decode the image. + */ + SDWebImageDownloaderAvoidDecodeImage = 1 << 9, + /** * By default, we decode the animated image. This flag can force decode the first frame only and produece the static image. */ - SDWebImageDownloaderDecodeFirstFrameOnly = 1 << 9, + SDWebImageDownloaderDecodeFirstFrameOnly = 1 << 10, /** * By default, for `SDAnimatedImage`, we decode the animated image frame during rendering to reduce memory usage. This flag actually trigger `preloadAllAnimatedImageFrames = YES` after image load from network */ - SDWebImageDownloaderPreloadAllFrames = 1 << 10 + SDWebImageDownloaderPreloadAllFrames = 1 << 11 }; FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStartNotification; diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 562d8979..4f356410 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -198,7 +198,6 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; operationClass = [SDWebImageDownloaderOperation class]; } NSOperation *operation = [[operationClass alloc] initWithRequest:request inSession:sself.session options:options context:context]; - operation.shouldDecompressImages = sself.config.shouldDecompressImages; if (sself.config.urlCredential) { operation.credential = sself.config.urlCredential; diff --git a/SDWebImage/SDWebImageDownloaderConfig.h b/SDWebImage/SDWebImageDownloaderConfig.h index 9f702bd6..8caf8d95 100644 --- a/SDWebImage/SDWebImageDownloaderConfig.h +++ b/SDWebImage/SDWebImageDownloaderConfig.h @@ -30,12 +30,6 @@ typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { */ @property (nonatomic, class, nonnull) SDWebImageDownloaderConfig *defaultDownloaderConfig; -/** - * Decompressing images that are downloaded and cached can improve performance but can consume lot of memory. - * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. - */ -@property (nonatomic, assign) BOOL shouldDecompressImages; - /** * The maximum number of concurrent downloads. * Defaults to 6. diff --git a/SDWebImage/SDWebImageDownloaderConfig.m b/SDWebImage/SDWebImageDownloaderConfig.m index 2d9d6136..869dbf1c 100644 --- a/SDWebImage/SDWebImageDownloaderConfig.m +++ b/SDWebImage/SDWebImageDownloaderConfig.m @@ -29,7 +29,6 @@ static SDWebImageDownloaderConfig * _defaultDownloaderConfig; - (instancetype)init { self = [super init]; if (self) { - _shouldDecompressImages = YES; _maxConcurrentDownloads = 6; _downloadTimeout = 15.0; _executionOrder = SDWebImageDownloaderFIFOExecutionOrder; @@ -39,7 +38,6 @@ static SDWebImageDownloaderConfig * _defaultDownloaderConfig; - (id)copyWithZone:(NSZone *)zone { SDWebImageDownloaderConfig *config = [[[self class] allocWithZone:zone] init]; - config.shouldDecompressImages = self.shouldDecompressImages; config.maxConcurrentDownloads = self.maxConcurrentDownloads; config.downloadTimeout = self.downloadTimeout; config.sessionConfiguration = [self.sessionConfiguration copyWithZone:zone]; diff --git a/SDWebImage/SDWebImageDownloaderOperation.h b/SDWebImage/SDWebImageDownloaderOperation.h index 2f776567..c5edfb1e 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.h +++ b/SDWebImage/SDWebImageDownloaderOperation.h @@ -36,9 +36,6 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification - (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock; -- (BOOL)shouldDecompressImages; -- (void)setShouldDecompressImages:(BOOL)value; - - (nullable NSURLCredential *)credential; - (void)setCredential:(nullable NSURLCredential *)value; @@ -70,12 +67,6 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification */ @property (strong, nonatomic, readonly, nullable) NSURLSessionTask *dataTask; -/** - * Decompressing images that are downloaded and cached can improve performance but can consume lot of memory. - * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. - */ -@property (assign, nonatomic) BOOL shouldDecompressImages; - /** * The credential used for authentication challenges in `-URLSession:task:didReceiveChallenge:completionHandler:`. * diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 49cd50cc..3c17b2fd 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -87,7 +87,6 @@ typedef NSMutableDictionary SDCallbacksDictionary; context:(nullable SDWebImageContext *)context { if ((self = [super init])) { _request = [request copy]; - _shouldDecompressImages = YES; _options = options; _context = [context copy]; _callbackBlocks = [NSMutableArray new]; @@ -379,7 +378,7 @@ didReceiveResponse:(NSURLResponse *)response image = [self.progressiveCoder incrementalDecodedImageWithOptions:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; } if (image) { - BOOL shouldDecode = self.shouldDecompressImages; + BOOL shouldDecode = (self.options & SDWebImageDownloaderAvoidDecodeImage) == 0; if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { // `SDAnimatedImage` do not decode shouldDecode = NO; @@ -479,7 +478,7 @@ didReceiveResponse:(NSURLResponse *)response image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; } - BOOL shouldDecode = self.shouldDecompressImages; + BOOL shouldDecode = (self.options & SDWebImageDownloaderAvoidDecodeImage) == 0; if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { // `SDAnimatedImage` do not decode shouldDecode = NO; diff --git a/SDWebImage/UIImage+ForceDecode.h b/SDWebImage/UIImage+ForceDecode.h index 25910abe..d0ec4bb7 100644 --- a/SDWebImage/UIImage+ForceDecode.h +++ b/SDWebImage/UIImage+ForceDecode.h @@ -16,27 +16,27 @@ @property (nonatomic, assign) BOOL sd_isDecoded; /** - Decompress (force decode before rendering) the provided image + Decode the provided image. This is useful if you want to force decode the image before rendering to improve performance. - @param image The image to be decompressed - @return The decompressed image + @param image The image to be decoded + @return The decoded image */ + (nullable UIImage *)sd_decodedImageWithImage:(nullable UIImage *)image; /** - Decompress and scale down the provided image + Decode and scale down the provided image - @param image The image to be decompressed - @return The decompressed and scaled down image + @param image The image to be decoded + @return The decoded and scaled down image */ + (nullable UIImage *)sd_decodedAndScaledDownImageWithImage:(nullable UIImage *)image; /** - Decompress and scale down the provided image and limit bytes + Decode and scale down the provided image with limit bytes - @param image The image to be decompressed + @param image The image to be decoded @param bytes The limit bytes size. Provide 0 to use the build-in limit. - @return The decompressed and scaled down image + @return The decoded and scaled down image */ + (nullable UIImage *)sd_decodedAndScaledDownImageWithImage:(nullable UIImage *)image limitBytes:(NSUInteger)bytes; diff --git a/Tests/Tests/SDWebImageTestDownloadOperation.h b/Tests/Tests/SDWebImageTestDownloadOperation.h index 90fcc55b..edc07b9c 100644 --- a/Tests/Tests/SDWebImageTestDownloadOperation.h +++ b/Tests/Tests/SDWebImageTestDownloadOperation.h @@ -15,7 +15,6 @@ */ @interface SDWebImageTestDownloadOperation : NSOperation -@property (nonatomic, assign) BOOL shouldDecompressImages; @property (nonatomic, strong, nullable) NSURLCredential *credential; @property (nonatomic, strong, nullable) NSURLRequest *request; @property (nonatomic, strong, nullable) NSURLResponse *response; From 62058d209d93715fd7118ef560b62f1959c8741c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 15 Apr 2018 00:05:09 +0800 Subject: [PATCH 125/361] Add memory cache and disk cache protocol, make our image cache just like a wrapper to call the disk cache implementation --- SDWebImage.xcodeproj/project.pbxproj | 56 ++++ SDWebImage/SDDiskCache.h | 107 ++++++++ SDWebImage/SDDiskCache.m | 232 +++++++++++++++++ SDWebImage/SDImageCache.h | 9 +- SDWebImage/SDImageCache.m | 372 +++++---------------------- SDWebImage/SDImageCacheConfig.h | 38 ++- SDWebImage/SDImageCacheConfig.m | 39 +++ SDWebImage/SDMemoryCache.h | 81 ++++++ SDWebImage/SDMemoryCache.m | 150 +++++++++++ Tests/Tests/SDImageCacheTests.m | 4 +- WebImage/SDWebImage.h | 2 + 11 files changed, 771 insertions(+), 319 deletions(-) create mode 100644 SDWebImage/SDDiskCache.h create mode 100644 SDWebImage/SDDiskCache.m create mode 100644 SDWebImage/SDMemoryCache.h create mode 100644 SDWebImage/SDMemoryCache.m diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index a718aecd..599add68 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -388,6 +388,30 @@ 327054DD206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; 327054DE206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; 327054DF206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; + 328BB6C12082581100760D6C /* SDDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BD2082581100760D6C /* SDDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6C22082581100760D6C /* SDDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BD2082581100760D6C /* SDDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6C32082581100760D6C /* SDDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BD2082581100760D6C /* SDDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6C42082581100760D6C /* SDDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BD2082581100760D6C /* SDDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6C52082581100760D6C /* SDDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BD2082581100760D6C /* SDDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6C62082581100760D6C /* SDDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BD2082581100760D6C /* SDDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6C72082581100760D6C /* SDDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6BE2082581100760D6C /* SDDiskCache.m */; }; + 328BB6C82082581100760D6C /* SDDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6BE2082581100760D6C /* SDDiskCache.m */; }; + 328BB6C92082581100760D6C /* SDDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6BE2082581100760D6C /* SDDiskCache.m */; }; + 328BB6CA2082581100760D6C /* SDDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6BE2082581100760D6C /* SDDiskCache.m */; }; + 328BB6CB2082581100760D6C /* SDDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6BE2082581100760D6C /* SDDiskCache.m */; }; + 328BB6CC2082581100760D6C /* SDDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6BE2082581100760D6C /* SDDiskCache.m */; }; + 328BB6CD2082581100760D6C /* SDMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BF2082581100760D6C /* SDMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6CE2082581100760D6C /* SDMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BF2082581100760D6C /* SDMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6CF2082581100760D6C /* SDMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BF2082581100760D6C /* SDMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6D02082581100760D6C /* SDMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BF2082581100760D6C /* SDMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6D12082581100760D6C /* SDMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BF2082581100760D6C /* SDMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6D22082581100760D6C /* SDMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB6BF2082581100760D6C /* SDMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 328BB6D32082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; + 328BB6D42082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; + 328BB6D52082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; + 328BB6D62082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; + 328BB6D72082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; + 328BB6D82082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; 3290FA041FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3290FA051FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3290FA061FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1492,6 +1516,10 @@ 325312C7200F09910046BF1E /* SDWebImageTransition.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransition.m; sourceTree = ""; }; 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageAPNGCoder.h; sourceTree = ""; }; 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageAPNGCoder.m; sourceTree = ""; }; + 328BB6BD2082581100760D6C /* SDDiskCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDDiskCache.h; sourceTree = ""; }; + 328BB6BE2082581100760D6C /* SDDiskCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDDiskCache.m; sourceTree = ""; }; + 328BB6BF2082581100760D6C /* SDMemoryCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDMemoryCache.h; sourceTree = ""; }; + 328BB6C02082581100760D6C /* SDMemoryCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDMemoryCache.m; sourceTree = ""; }; 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageFrame.h; sourceTree = ""; }; 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageFrame.m; sourceTree = ""; }; 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImage+WebCache.h"; path = "SDWebImage/UIImage+WebCache.h"; sourceTree = ""; }; @@ -1985,6 +2013,10 @@ 53922D86148C56230056699D /* SDImageCache.m */, 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */, 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */, + 328BB6BF2082581100760D6C /* SDMemoryCache.h */, + 328BB6C02082581100760D6C /* SDMemoryCache.m */, + 328BB6BD2082581100760D6C /* SDDiskCache.h */, + 328BB6BE2082581100760D6C /* SDDiskCache.m */, ); name = Cache; sourceTree = ""; @@ -2238,6 +2270,7 @@ 431739551CDFC8B70008FEB9 /* decode.h in Headers */, 00733A731BC4880E00A5A117 /* SDWebImage.h in Headers */, 323F8B651F38EF770092B609 /* cost_enc.h in Headers */, + 328BB6C42082581100760D6C /* SDDiskCache.h in Headers */, 00733A701BC4880E00A5A117 /* UIImageView+HighlightedWebCache.h in Headers */, 323F8BDB1F38EF770092B609 /* vp8i_enc.h in Headers */, 80377C461F2F666300F89830 /* bit_reader_inl_utils.h in Headers */, @@ -2246,6 +2279,7 @@ 00733A631BC4880E00A5A117 /* SDWebImageCompat.h in Headers */, 00733A661BC4880E00A5A117 /* SDWebImageDownloaderOperation.h in Headers */, 80377C5D1F2F666300F89830 /* thread_utils.h in Headers */, + 328BB6D02082581100760D6C /* SDMemoryCache.h in Headers */, 321E60891F38E8C800405457 /* SDWebImageCoder.h in Headers */, 00733A721BC4880E00A5A117 /* UIView+WebCacheOperation.h in Headers */, 80377C481F2F666300F89830 /* bit_reader_utils.h in Headers */, @@ -2356,6 +2390,7 @@ 4314D17D1D0E0E3B004B36C9 /* SDWebImagePrefetcher.h in Headers */, 80377C181F2F666300F89830 /* color_cache_utils.h in Headers */, 323F8B871F38EF770092B609 /* histogram_enc.h in Headers */, + 328BB6CE2082581100760D6C /* SDMemoryCache.h in Headers */, 80377C1F1F2F666300F89830 /* huffman_utils.h in Headers */, 4314D17F1D0E0E3B004B36C9 /* UIButton+WebCache.h in Headers */, 32484764201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, @@ -2364,6 +2399,7 @@ 4314D1851D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.h in Headers */, 4314D1861D0E0E3B004B36C9 /* UIImageView+HighlightedWebCache.h in Headers */, 4314D1881D0E0E3B004B36C9 /* format_constants.h in Headers */, + 328BB6C22082581100760D6C /* SDDiskCache.h in Headers */, 323F8B631F38EF770092B609 /* cost_enc.h in Headers */, 323F8BF71F38EF770092B609 /* animi.h in Headers */, 4314D18F1D0E0E3B004B36C9 /* UIView+WebCacheOperation.h in Headers */, @@ -2421,6 +2457,7 @@ 325312CC200F09910046BF1E /* SDWebImageTransition.h in Headers */, 80377C6D1F2F666400F89830 /* huffman_utils.h in Headers */, 80377C731F2F666400F89830 /* random_utils.h in Headers */, + 328BB6C52082581100760D6C /* SDDiskCache.h in Headers */, 431BB6EE1D06D2C1006A3455 /* NSData+ImageContentType.h in Headers */, 431BB6EF1D06D2C1006A3455 /* SDWebImagePrefetcher.h in Headers */, 80377C671F2F666400F89830 /* endian_inl_utils.h in Headers */, @@ -2432,6 +2469,7 @@ 323F8B8A1F38EF770092B609 /* histogram_enc.h in Headers */, 80377E1E1F2F66A800F89830 /* lossless.h in Headers */, 321E60981F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, + 328BB6D12082581100760D6C /* SDMemoryCache.h in Headers */, 4369C27B1D9807EC007E863A /* UIView+WebCache.h in Headers */, 80377ED11F2F66D500F89830 /* vp8_dec.h in Headers */, 324DF4B8200A14DC008A84CC /* SDWebImageDefine.h in Headers */, @@ -2505,6 +2543,7 @@ 3248477A201775F600AF9E5A /* SDAnimatedImage.h in Headers */, 329A185E1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 320224BB203979BA00E9F285 /* SDAnimatedImageRep.h in Headers */, + 328BB6C62082581100760D6C /* SDDiskCache.h in Headers */, 80377E761F2F66A800F89830 /* yuv.h in Headers */, 80377C7A1F2F666400F89830 /* bit_reader_inl_utils.h in Headers */, 80377E631F2F66A800F89830 /* lossless.h in Headers */, @@ -2513,6 +2552,7 @@ 4397D2D81D0DDD8C00BB2784 /* UIButton+WebCache.h in Headers */, 32F7C0742030114C00873181 /* SDWebImageTransformer.h in Headers */, 80377E641F2F66A800F89830 /* mips_macro.h in Headers */, + 328BB6D22082581100760D6C /* SDMemoryCache.h in Headers */, 323F8BDD1F38EF770092B609 /* vp8i_enc.h in Headers */, 323F8B671F38EF770092B609 /* cost_enc.h in Headers */, 80377EE11F2F66D500F89830 /* vp8_dec.h in Headers */, @@ -2597,6 +2637,7 @@ 4A2CAE331AB4BB7500B6BC39 /* UIImageView+HighlightedWebCache.h in Headers */, 431739521CDFC8B70008FEB9 /* mux.h in Headers */, 323F8B641F38EF770092B609 /* cost_enc.h in Headers */, + 328BB6C32082581100760D6C /* SDDiskCache.h in Headers */, 4A2CAE1D1AB4BB6800B6BC39 /* SDWebImageDownloaderOperation.h in Headers */, 323F8BDA1F38EF770092B609 /* vp8i_enc.h in Headers */, 4317394E1CDFC8B70008FEB9 /* decode.h in Headers */, @@ -2605,6 +2646,7 @@ 4A2CAE2B1AB4BB7500B6BC39 /* UIButton+WebCache.h in Headers */, 4A2CAE251AB4BB7000B6BC39 /* SDWebImagePrefetcher.h in Headers */, 80377C431F2F666300F89830 /* thread_utils.h in Headers */, + 328BB6CF2082581100760D6C /* SDMemoryCache.h in Headers */, 321E60881F38E8C800405457 /* SDWebImageCoder.h in Headers */, 4A2CAE371AB4BB7500B6BC39 /* UIView+WebCacheOperation.h in Headers */, 80377C2E1F2F666300F89830 /* bit_reader_utils.h in Headers */, @@ -2663,6 +2705,7 @@ 321E60A21F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, 5D5B9142188EE8DD006D06BD /* NSData+ImageContentType.h in Headers */, 80377BFE1F2F665300F89830 /* color_cache_utils.h in Headers */, + 328BB6C12082581100760D6C /* SDDiskCache.h in Headers */, 431738C11CDFC2660008FEB9 /* mux.h in Headers */, 80377D0A1F2F66A100F89830 /* lossless.h in Headers */, 53761318155AD0D5005750A4 /* SDWebImageCompat.h in Headers */, @@ -2682,6 +2725,7 @@ 80377D0B1F2F66A100F89830 /* mips_macro.h in Headers */, 329A18591FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 5376131A155AD0D5005750A4 /* SDWebImageDownloader.h in Headers */, + 328BB6CD2082581100760D6C /* SDMemoryCache.h in Headers */, 4369C2771D9807EC007E863A /* UIView+WebCache.h in Headers */, 80377CEF1F2F66A100F89830 /* dsp.h in Headers */, 32F21B5120788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, @@ -2984,6 +3028,7 @@ 32CF1C101FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */, 80377DAE1F2F66A700F89830 /* argb_sse2.c in Sources */, 323F8B7D1F38EF770092B609 /* frame_enc.c in Sources */, + 328BB6D62082581100760D6C /* SDMemoryCache.m in Sources */, 80377EBB1F2F66D500F89830 /* frame_dec.c in Sources */, 32F7C0782030114C00873181 /* SDWebImageTransformer.m in Sources */, 80377DAF1F2F66A700F89830 /* argb.c in Sources */, @@ -3032,6 +3077,7 @@ 80377EBF1F2F66D500F89830 /* tree_dec.c in Sources */, 80377DD21F2F66A700F89830 /* lossless_enc_sse41.c in Sources */, 80377DB31F2F66A700F89830 /* cost_sse2.c in Sources */, + 328BB6CA2082581100760D6C /* SDDiskCache.m in Sources */, 32484760201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 80377DDE1F2F66A700F89830 /* rescaler_mips32.c in Sources */, 80377DCA1F2F66A700F89830 /* filters_sse2.c in Sources */, @@ -3194,6 +3240,7 @@ 80377E9B1F2F66D400F89830 /* frame_dec.c in Sources */, 80377C1C1F2F666300F89830 /* huffman_encode_utils.c in Sources */, 323F8B451F38EF770092B609 /* analysis_enc.c in Sources */, + 328BB6C82082581100760D6C /* SDDiskCache.m in Sources */, 80377C261F2F666300F89830 /* rescaler_utils.c in Sources */, 323F8BBB1F38EF770092B609 /* predictor_enc.c in Sources */, 325312CF200F09910046BF1E /* SDWebImageTransition.m in Sources */, @@ -3232,6 +3279,7 @@ 327054DB206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */, 80377D5C1F2F66A700F89830 /* upsampling_sse2.c in Sources */, 323F8BC71F38EF770092B609 /* syntax_enc.c in Sources */, + 328BB6D42082581100760D6C /* SDMemoryCache.m in Sources */, 80377D321F2F66A700F89830 /* dec_sse41.c in Sources */, 324DF4BB200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 80377D451F2F66A700F89830 /* lossless_enc_msa.c in Sources */, @@ -3351,6 +3399,7 @@ 80377C721F2F666400F89830 /* random_utils.c in Sources */, 80377ECB1F2F66D500F89830 /* frame_dec.c in Sources */, 80377C6A1F2F666400F89830 /* huffman_encode_utils.c in Sources */, + 328BB6CB2082581100760D6C /* SDDiskCache.m in Sources */, 323F8B481F38EF770092B609 /* analysis_enc.c in Sources */, 80377DFE1F2F66A800F89830 /* dec_msa.c in Sources */, 325312D2200F09910046BF1E /* SDWebImageTransition.m in Sources */, @@ -3389,6 +3438,7 @@ 327054DE206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */, 80377DFD1F2F66A800F89830 /* dec_mips32.c in Sources */, 323F8BCA1F38EF770092B609 /* syntax_enc.c in Sources */, + 328BB6D72082581100760D6C /* SDMemoryCache.m in Sources */, 80377E2B1F2F66A800F89830 /* upsampling_sse2.c in Sources */, 324DF4BE200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 80377E011F2F66A800F89830 /* dec_sse41.c in Sources */, @@ -3454,6 +3504,7 @@ 323F8BEF1F38EF770092B609 /* webp_enc.c in Sources */, 323F8BA11F38EF770092B609 /* picture_csp_enc.c in Sources */, 323F8C1F1F38EF770092B609 /* muxread.c in Sources */, + 328BB6CC2082581100760D6C /* SDDiskCache.m in Sources */, 323F8C0D1F38EF770092B609 /* muxedit.c in Sources */, 323F8B491F38EF770092B609 /* analysis_enc.c in Sources */, 80377E6E1F2F66A800F89830 /* upsampling_msa.c in Sources */, @@ -3476,6 +3527,7 @@ 80377E4E1F2F66A800F89830 /* enc_sse2.c in Sources */, 80377E6C1F2F66A800F89830 /* rescaler.c in Sources */, 32484762201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, + 328BB6D82082581100760D6C /* SDMemoryCache.m in Sources */, 80377EE31F2F66D500F89830 /* vp8l_dec.c in Sources */, 80377ED71F2F66D500F89830 /* alpha_dec.c in Sources */, 323F8B7F1F38EF770092B609 /* frame_enc.c in Sources */, @@ -3618,6 +3670,7 @@ 32CF1C0F1FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */, 80377D6A1F2F66A700F89830 /* argb.c in Sources */, 323F8B7C1F38EF770092B609 /* frame_enc.c in Sources */, + 328BB6D52082581100760D6C /* SDMemoryCache.m in Sources */, 80377EAB1F2F66D400F89830 /* frame_dec.c in Sources */, 32F7C0772030114C00873181 /* SDWebImageTransformer.m in Sources */, 43C8929D1D9D6DD90022038D /* anim_decode.c in Sources */, @@ -3666,6 +3719,7 @@ 80377EAF1F2F66D400F89830 /* tree_dec.c in Sources */, 4A2CAE281AB4BB7500B6BC39 /* MKAnnotationView+WebCache.m in Sources */, 4A2CAE261AB4BB7000B6BC39 /* SDWebImagePrefetcher.m in Sources */, + 328BB6C92082581100760D6C /* SDDiskCache.m in Sources */, 3248475F201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 80377C441F2F666300F89830 /* utils.c in Sources */, 80377D8D1F2F66A700F89830 /* lossless_enc_sse41.c in Sources */, @@ -3779,6 +3833,7 @@ 32CF1C0D1FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */, 323F8B7A1F38EF770092B609 /* frame_enc.c in Sources */, 80377E8B1F2F66D000F89830 /* frame_dec.c in Sources */, + 328BB6D32082581100760D6C /* SDMemoryCache.m in Sources */, 43C8929A1D9D6DD70022038D /* anim_decode.c in Sources */, 32F7C0752030114C00873181 /* SDWebImageTransformer.m in Sources */, 323F8B681F38EF770092B609 /* delta_palettization_enc.c in Sources */, @@ -3827,6 +3882,7 @@ 5376130C155AD0D5005750A4 /* SDWebImageManager.m in Sources */, 5376130D155AD0D5005750A4 /* SDWebImagePrefetcher.m in Sources */, 80377C101F2F665300F89830 /* utils.c in Sources */, + 328BB6C72082581100760D6C /* SDDiskCache.m in Sources */, 3248475D201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 80377D031F2F66A100F89830 /* lossless_enc_sse41.c in Sources */, 80377E8E1F2F66D000F89830 /* quant_dec.c in Sources */, diff --git a/SDWebImage/SDDiskCache.h b/SDWebImage/SDDiskCache.h new file mode 100644 index 00000000..0a12ff31 --- /dev/null +++ b/SDWebImage/SDDiskCache.h @@ -0,0 +1,107 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +@class SDImageCacheConfig; +// A protocol to allow custom disk cache used in SDImageCache. +@protocol SDDiskCache + +// All of these method are called from the same global queue to avoid blocking on main queue and thread-safe problem. But it's also recommend to ensure thread-safe yourself using lock or other ways. +@required +/** + Create a new disk cache based on the specified path. + + @param cachePath Full path of a directory in which the cache will write data. + Once initialized you should not read and write to this directory. + @param config The cache config to be used to create the cache. + + @return A new cache object, or nil if an error occurs. + */ +- (nullable instancetype)initWithCachePath:(nonnull NSString *)cachePath config:(nonnull SDImageCacheConfig *)config; + +/** + Returns a boolean value that indicates whether a given key is in cache. + This method may blocks the calling thread until file read finished. + + @param key A string identifying the data. If nil, just return NO. + @return Whether the key is in cache. + */ +- (BOOL)containsDataForKey:(nonnull NSString *)key; + +/** + Returns the data associated with a given key. + This method may blocks the calling thread until file read finished. + + @param key A string identifying the data. If nil, just return nil. + @return The value associated with key, or nil if no value is associated with key. + */ +- (nullable NSData *)dataForKey:(nonnull NSString *)key; + +/** + Sets the value of the specified key in the cache. + This method may blocks the calling thread until file write finished. + + @param data The data to be stored in the cache. + @param key The key with which to associate the value. If nil, this method has no effect. + */ +- (void)setData:(nullable NSData *)data forKey:(nonnull NSString *)key; + +/** + Removes the value of the specified key in the cache. + This method may blocks the calling thread until file delete finished. + + @param key The key identifying the value to be removed. If nil, this method has no effect. + */ +- (void)removeDataForKey:(nonnull NSString *)key; + +/** + Empties the cache. + This method may blocks the calling thread until file delete finished. + */ +- (void)removeAllData; + +/** + Removes the expired data from the cache. You can choose the data to remove base on `ageLimit`, `countLimit` and `sizeLimit` options. + */ +- (void)removeExpiredData; + +/** + The cache path for key + + @param key A string identifying the value + @return The cache path for key. Or nil if the key can not associate to a path + */ +- (nullable NSString *)cachePathForKey:(nonnull NSString *)key; + +/** + Returns the number of data in this cache. + This method may blocks the calling thread until file read finished. + + @return The total data count. + */ +- (NSInteger)totalCount; + +/** + Returns the total size (in bytes) of data in this cache. + This method may blocks the calling thread until file read finished. + + @return The total data size in bytes. + */ +- (NSInteger)totalSize; + +@end + +// The built-in disk cache +@interface SDDiskCache : NSObject + +@property (nonatomic, strong, readonly, nonnull) SDImageCacheConfig *config; + +- (nonnull instancetype)init NS_UNAVAILABLE; + +@end diff --git a/SDWebImage/SDDiskCache.m b/SDWebImage/SDDiskCache.m new file mode 100644 index 00000000..0e0064e4 --- /dev/null +++ b/SDWebImage/SDDiskCache.m @@ -0,0 +1,232 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDDiskCache.h" +#import "SDImageCacheConfig.h" +#import + +@interface SDDiskCache () + +@property (nonatomic, copy) NSString *diskCachePath; +@property (nonatomic, strong, nonnull) NSFileManager *fileManager; + +@end + +@implementation SDDiskCache + +- (instancetype)init { + NSAssert(NO, @"Use `initWithCachePath:` with the disk cache path"); + return nil; +} + +#pragma mark - SDcachePathForKeyDiskCache Protocol +- (instancetype)initWithCachePath:(NSString *)cachePath config:(nonnull SDImageCacheConfig *)config { + if (self = [super init]) { + _diskCachePath = cachePath; + _config = config; + [self commonInit]; + } + return self; +} + +- (void)commonInit { + if (self.config.fileManager) { + self.fileManager = self.config.fileManager; + } else { + self.fileManager = [NSFileManager new]; + } +} + +- (BOOL)containsDataForKey:(NSString *)key { + NSParameterAssert(key); + NSString *filePath = [self cachePathForKey:key]; + BOOL exists = [self.fileManager fileExistsAtPath:filePath]; + + // fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name + // checking the key with and without the extension + if (!exists) { + exists = [self.fileManager fileExistsAtPath:filePath.stringByDeletingPathExtension]; + } + + return exists; +} + +- (NSData *)dataForKey:(NSString *)key { + NSParameterAssert(key); + NSString *filePath = [self cachePathForKey:key]; + NSData *data = [NSData dataWithContentsOfFile:filePath options:self.config.diskCacheReadingOptions error:nil]; + if (data) { + return data; + } + + // fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name + // checking the key with and without the extension + data = [NSData dataWithContentsOfFile:filePath.stringByDeletingPathExtension options:self.config.diskCacheReadingOptions error:nil]; + if (data) { + return data; + } + + return nil; +} + +- (void)setData:(NSData *)data forKey:(NSString *)key { + NSParameterAssert(data); + NSParameterAssert(key); + if (![self.fileManager fileExistsAtPath:self.diskCachePath]) { + [self.fileManager createDirectoryAtPath:self.diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL]; + } + + // get cache Path for image key + NSString *cachePathForKey = [self cachePathForKey:key]; + // transform to NSUrl + NSURL *fileURL = [NSURL fileURLWithPath:cachePathForKey]; + + [data writeToURL:fileURL options:self.config.diskCacheWritingOptions error:nil]; + + // disable iCloud backup + if (self.config.shouldDisableiCloud) { + // ignore iCloud backup resource value error + [fileURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil]; + } +} + +- (void)removeDataForKey:(NSString *)key { + NSParameterAssert(key); + NSString *filePath = [self cachePathForKey:key]; + [self.fileManager removeItemAtPath:filePath error:nil]; +} + +- (void)removeAllData { + [self.fileManager removeItemAtPath:self.diskCachePath error:nil]; + [self.fileManager createDirectoryAtPath:self.diskCachePath + withIntermediateDirectories:YES + attributes:nil + error:NULL]; +} + +- (void)removeExpiredData { + NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES]; + NSArray *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey]; + + // This enumerator prefetches useful properties for our cache files. + NSDirectoryEnumerator *fileEnumerator = [self.fileManager enumeratorAtURL:diskCacheURL + includingPropertiesForKeys:resourceKeys + options:NSDirectoryEnumerationSkipsHiddenFiles + errorHandler:NULL]; + + NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.config.maxCacheAge]; + NSMutableDictionary *> *cacheFiles = [NSMutableDictionary dictionary]; + NSUInteger currentCacheSize = 0; + + // Enumerate all of the files in the cache directory. This loop has two purposes: + // + // 1. Removing files that are older than the expiration date. + // 2. Storing file attributes for the size-based cleanup pass. + NSMutableArray *urlsToDelete = [[NSMutableArray alloc] init]; + for (NSURL *fileURL in fileEnumerator) { + NSError *error; + NSDictionary *resourceValues = [fileURL resourceValuesForKeys:resourceKeys error:&error]; + + // Skip directories and errors. + if (error || !resourceValues || [resourceValues[NSURLIsDirectoryKey] boolValue]) { + continue; + } + + // Remove files that are older than the expiration date; + NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey]; + if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) { + [urlsToDelete addObject:fileURL]; + continue; + } + + // Store a reference to this file and account for its total size. + NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey]; + currentCacheSize += totalAllocatedSize.unsignedIntegerValue; + cacheFiles[fileURL] = resourceValues; + } + + for (NSURL *fileURL in urlsToDelete) { + [self.fileManager removeItemAtURL:fileURL error:nil]; + } + + // If our remaining disk cache exceeds a configured maximum size, perform a second + // size-based cleanup pass. We delete the oldest files first. + NSUInteger maxCacheSize = self.config.maxCacheSize; + if (maxCacheSize > 0 && currentCacheSize > maxCacheSize) { + // Target half of our maximum cache size for this cleanup pass. + const NSUInteger desiredCacheSize = maxCacheSize / 2; + + // Sort the remaining cache files by their last modification time (oldest first). + NSArray *sortedFiles = [cacheFiles keysSortedByValueWithOptions:NSSortConcurrent + usingComparator:^NSComparisonResult(id obj1, id obj2) { + return [obj1[NSURLContentModificationDateKey] compare:obj2[NSURLContentModificationDateKey]]; + }]; + + // Delete files until we fall below our desired cache size. + for (NSURL *fileURL in sortedFiles) { + if ([self.fileManager removeItemAtURL:fileURL error:nil]) { + NSDictionary *resourceValues = cacheFiles[fileURL]; + NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey]; + currentCacheSize -= totalAllocatedSize.unsignedIntegerValue; + + if (currentCacheSize < desiredCacheSize) { + break; + } + } + } + } +} + +- (nullable NSString *)cachePathForKey:(NSString *)key { + NSParameterAssert(key); + return [self cachePathForKey:key inPath:self.diskCachePath]; +} + +- (NSInteger)totalSize { + NSUInteger size = 0; + NSDirectoryEnumerator *fileEnumerator = [self.fileManager enumeratorAtPath:self.diskCachePath]; + for (NSString *fileName in fileEnumerator) { + NSString *filePath = [self.diskCachePath stringByAppendingPathComponent:fileName]; + NSDictionary *attrs = [self.fileManager attributesOfItemAtPath:filePath error:nil]; + size += [attrs fileSize]; + } + return size; +} + +- (NSInteger)totalCount { + NSUInteger count = 0; + NSDirectoryEnumerator *fileEnumerator = [self.fileManager enumeratorAtPath:self.diskCachePath]; + count = fileEnumerator.allObjects.count; + return count; +} + +#pragma mark - Cache paths + +- (nullable NSString *)cachePathForKey:(nullable NSString *)key inPath:(nonnull NSString *)path { + NSString *filename = SDDiskCacheFileNameForKey(key); + return [path stringByAppendingPathComponent:filename]; +} + +#pragma mark - Hash + +static inline NSString * _Nullable SDDiskCacheFileNameForKey(NSString * _Nullable key) { + const char *str = key.UTF8String; + if (str == NULL) { + return nil; + } + unsigned char r[CC_MD5_DIGEST_LENGTH]; + CC_MD5(str, (CC_LONG)strlen(str), r); + NSURL *keyURL = [NSURL URLWithString:key]; + NSString *ext = keyURL ? keyURL.pathExtension : key.pathExtension; + NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%@", + r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10], + r[11], r[12], r[13], r[14], r[15], ext.length == 0 ? @"" : [NSString stringWithFormat:@".%@", ext]]; + return filename; +} + +@end diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 1adee32f..a04221fc 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -72,9 +72,10 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * #pragma mark - Properties /** - * Cache Config object - storing all kind of settings + * Cache Config object - storing all kind of settings. + * The property is copy so change of currrent config will not accidentally affect other cache's config. */ -@property (nonatomic, nonnull, readonly) SDImageCacheConfig *config; +@property (nonatomic, copy, nonnull, readonly) SDImageCacheConfig *config; /** * The disk cache's root path @@ -116,11 +117,11 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * * * @param ns The namespace to use for this cache store * @param directory Directory to cache disk images in - * @param fileManager The file manager for storing image, if nil then will be created new one + * @param config The cache config to be used to create the cache. You can provide custom memory cache or disk cache class in the cache config */ - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns diskCacheDirectory:(nonnull NSString *)directory - fileManager:(nullable NSFileManager *)fileManager NS_DESIGNATED_INITIALIZER; + config:(nullable SDImageCacheConfig *)config NS_DESIGNATED_INITIALIZER; #pragma mark - Cache paths diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 96498460..e689c76f 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -7,7 +7,8 @@ */ #import "SDImageCache.h" -#import +#import "SDMemoryCache.h" +#import "SDDiskCache.h" #import "NSImage+Additions.h" #import "UIImage+WebCache.h" #import "SDWebImageCodersManager.h" @@ -15,121 +16,14 @@ #import "SDWebImageCoderHelper.h" #import "SDAnimatedImage.h" -#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); -#define UNLOCK(lock) dispatch_semaphore_signal(lock); - -static void * SDImageCacheContext = &SDImageCacheContext; - -FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { -#if SD_MAC - return image.size.height * image.size.width; -#elif SD_UIKIT || SD_WATCH - return image.size.height * image.size.width * image.scale * image.scale; -#endif -} - -// A memory cache which auto purge the cache on memory warning and support weak cache. -@interface SDMemoryCache : NSCache - -@end - -// Private -@interface SDMemoryCache () - -@property (nonatomic, strong, nonnull) NSMapTable *weakCache; // strong-weak cache -@property (nonatomic, strong, nonnull) dispatch_semaphore_t weakCacheLock; // a lock to keep the access to `weakCache` thread-safe - -@end - -@implementation SDMemoryCache - -// Current this seems no use on macOS (macOS use virtual memory and do not clear cache when memory warning). So we only override on iOS/tvOS platform. -// But in the future there may be more options and features for this subclass. -#if SD_UIKIT - -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; -} - -- (instancetype)init { - self = [super init]; - if (self) { - // Use a strong-weak maptable storing the secondary cache. Follow the doc that NSCache does not copy keys - // This is useful when the memory warning, the cache was purged. However, the image instance can be retained by other instance such as imageViews and alive. - // At this case, we can sync weak cache back and do not need to load from disk cache - self.weakCache = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory capacity:0]; - self.weakCacheLock = dispatch_semaphore_create(1); - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(didReceiveMemoryWarning:) - name:UIApplicationDidReceiveMemoryWarningNotification - object:nil]; - } - return self; -} - -- (void)didReceiveMemoryWarning:(NSNotification *)notification { - // Only remove cache, but keep weak cache - [super removeAllObjects]; -} - -// `setObject:forKey:` just call this with 0 cost. Override this is enough -- (void)setObject:(id)obj forKey:(id)key cost:(NSUInteger)g { - [super setObject:obj forKey:key cost:g]; - if (key && obj) { - // Store weak cache - LOCK(self.weakCacheLock); - [self.weakCache setObject:obj forKey:key]; - UNLOCK(self.weakCacheLock); - } -} - -- (id)objectForKey:(id)key { - id obj = [super objectForKey:key]; - if (key && !obj) { - // Check weak cache - LOCK(self.weakCacheLock); - obj = [self.weakCache objectForKey:key]; - UNLOCK(self.weakCacheLock); - if (obj) { - // Sync cache - NSUInteger cost = 0; - if ([obj isKindOfClass:[UIImage class]]) { - cost = SDCacheCostForImage(obj); - } - [super setObject:obj forKey:key cost:cost]; - } - } - return obj; -} - -- (void)removeObjectForKey:(id)key { - [super removeObjectForKey:key]; - if (key) { - // Remove weak cache - LOCK(self.weakCacheLock); - [self.weakCache removeObjectForKey:key]; - UNLOCK(self.weakCacheLock); - } -} - -- (void)removeAllObjects { - [super removeAllObjects]; - // Manually remove should also remove weak cache - LOCK(self.weakCacheLock); - [self.weakCache removeAllObjects]; - UNLOCK(self.weakCacheLock); -} - -#endif - -@end - @interface SDImageCache () #pragma mark - Properties -@property (strong, nonatomic, nonnull) SDMemoryCache *memCache; -@property (strong, nonatomic, nullable) dispatch_queue_t ioQueue; -@property (strong, nonatomic, nonnull) NSFileManager *fileManager; +@property (nonatomic, strong, nonnull) id memCache; +@property (nonatomic, strong, nonnull) id diskCache; +@property (nonatomic, copy, readwrite, nonnull) SDImageCacheConfig *config; +@property (nonatomic, copy, readwrite, nonnull) NSString *diskCachePath; +@property (nonatomic, strong, nullable) dispatch_queue_t ioQueue; @end @@ -158,27 +52,27 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns diskCacheDirectory:(nonnull NSString *)directory { - return [self initWithNamespace:ns diskCacheDirectory:directory fileManager: nil]; + return [self initWithNamespace:ns diskCacheDirectory:directory config:SDImageCacheConfig.defaultCacheConfig]; } - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns diskCacheDirectory:(nonnull NSString *)directory - fileManager:(nullable NSFileManager *)fileManager { + config:(nullable SDImageCacheConfig *)config { if ((self = [super init])) { NSString *fullNamespace = [@"com.hackemist.SDWebImageCache." stringByAppendingString:ns]; // Create IO serial queue _ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL); - _config = [[SDImageCacheConfig alloc] init]; - // KVO config property which need to be passed - [_config addObserver:self forKeyPath:NSStringFromSelector(@selector(maxMemoryCost)) options:0 context:SDImageCacheContext]; - [_config addObserver:self forKeyPath:NSStringFromSelector(@selector(maxMemoryCount)) options:0 context:SDImageCacheContext]; + if (!config) { + config = SDImageCacheConfig.defaultCacheConfig; + } + _config = [config copy]; // Init the memory cache - _memCache = [[SDMemoryCache alloc] init]; - _memCache.name = fullNamespace; - + NSAssert([config.memoryCacheClass conformsToProtocol:@protocol(SDMemoryCache)], @"Custom memory cache class must conform to `SDMemoryCache` protocol"); + _memCache = [[config.memoryCacheClass alloc] initWithConfig:_config]; + // Init the disk cache if (directory != nil) { _diskCachePath = [directory stringByAppendingPathComponent:fullNamespace]; @@ -186,22 +80,27 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { NSString *path = [self makeDiskCachePath:ns]; _diskCachePath = path; } - - dispatch_sync(_ioQueue, ^{ - self.fileManager = fileManager ? fileManager : [NSFileManager new]; - }); + + NSAssert([config.diskCacheClass conformsToProtocol:@protocol(SDDiskCache)], @"Custom disk cache class must conform to `SDDiskCache` protocol"); + _diskCache = [[config.diskCacheClass alloc] initWithCachePath:_diskCachePath config:_config]; #if SD_UIKIT // Subscribe to app events [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(deleteOldFiles) + selector:@selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(backgroundDeleteOldFiles) + selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; +#endif +#if SD_MAC + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(applicationWillTerminate:) + name:NSApplicationWillTerminateNotification + object:nil]; #endif } @@ -209,8 +108,6 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } - (void)dealloc { - [_config removeObserver:self forKeyPath:NSStringFromSelector(@selector(maxMemoryCost)) context:SDImageCacheContext]; - [_config removeObserver:self forKeyPath:NSStringFromSelector(@selector(maxMemoryCount)) context:SDImageCacheContext]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } @@ -220,27 +117,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (!key) { return nil; } - return [self cachePathForKey:key inPath:self.diskCachePath]; -} - -- (nullable NSString *)cachePathForKey:(nullable NSString *)key inPath:(nonnull NSString *)path { - NSString *filename = [self cachedFileNameForKey:key]; - return [path stringByAppendingPathComponent:filename]; -} - -- (nullable NSString *)cachedFileNameForKey:(nullable NSString *)key { - const char *str = key.UTF8String; - if (str == NULL) { - str = ""; - } - unsigned char r[CC_MD5_DIGEST_LENGTH]; - CC_MD5(str, (CC_LONG)strlen(str), r); - NSURL *keyURL = [NSURL URLWithString:key]; - NSString *ext = keyURL ? keyURL.pathExtension : key.pathExtension; - NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%@", - r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10], - r[11], r[12], r[13], r[14], r[15], ext.length == 0 ? @"" : [NSString stringWithFormat:@".%@", ext]]; - return filename; + return [self.diskCache cachePathForKey:key]; } - (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace { @@ -276,7 +153,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } // if memory cache is enabled if (self.config.shouldCacheImagesInMemory) { - NSUInteger cost = SDCacheCostForImage(image); + NSUInteger cost = SDMemoryCacheCostForImage(image); [self.memCache setObject:image forKey:key cost:cost]; } @@ -326,28 +203,8 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (!imageData || !key) { return; } - if (![self.fileManager fileExistsAtPath:_diskCachePath]) { - if (![self.fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:nil]) { - return; - } - } - // get cache Path for image key - NSString *cachePathForKey = [self cachePathForKey:key]; - // transform to NSUrl - NSURL *fileURL = [NSURL fileURLWithPath:cachePathForKey]; - - // NSFileManager's `createFileAtPath:` is used just for old code compatibility and will not trigger any delegate methods, so it's useless for custom NSFileManager at all. - // And also, NSFileManager's `createFileAtPath:` can only grab underlying POSIX errno, but NSData can grab errors defined in NSCocoaErrorDomain, which is better for user to check. - if (![imageData writeToURL:fileURL options:self.config.diskCacheWritingOptions error:nil]) { - return; - } - - // disable iCloud backup - if (self.config.shouldDisableiCloud) { - // ignore iCloud backup resource value error - [fileURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil]; - } + [self.diskCache setData:imageData forKey:key]; } #pragma mark - Query and Retrieve Ops @@ -381,15 +238,8 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (!key) { return NO; } - BOOL exists = [self.fileManager fileExistsAtPath:[self cachePathForKey:key]]; - // fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name - // checking the key with and without the extension - if (!exists) { - exists = [self.fileManager fileExistsAtPath:[self cachePathForKey:key].stringByDeletingPathExtension]; - } - - return exists; + return [self.diskCache containsDataForKey:key]; } - (nullable UIImage *)imageFromMemoryCacheForKey:(nullable NSString *)key { @@ -399,7 +249,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { - (nullable UIImage *)imageFromDiskCacheForKey:(nullable NSString *)key { UIImage *diskImage = [self diskImageForKey:key]; if (diskImage && self.config.shouldCacheImagesInMemory) { - NSUInteger cost = SDCacheCostForImage(diskImage); + NSUInteger cost = SDMemoryCacheCostForImage(diskImage); [self.memCache setObject:diskImage forKey:key cost:cost]; } @@ -419,15 +269,11 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } - (nullable NSData *)diskImageDataBySearchingAllPathsForKey:(nullable NSString *)key { - NSString *defaultPath = [self cachePathForKey:key]; - NSData *data = [NSData dataWithContentsOfFile:defaultPath options:self.config.diskCacheReadingOptions error:nil]; - if (data) { - return data; + if (!key) { + return nil; } - - // fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name - // checking the key with and without the extension - data = [NSData dataWithContentsOfFile:defaultPath.stringByDeletingPathExtension options:self.config.diskCacheReadingOptions error:nil]; + + NSData *data = [self.diskCache dataForKey:key]; if (data) { return data; } @@ -542,7 +388,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { // decode image data only if in-memory cache missed diskImage = [self diskImageForKey:cacheKey data:diskData options:options context:context]; if (diskImage && self.config.shouldCacheImagesInMemory) { - NSUInteger cost = SDCacheCostForImage(diskImage); + NSUInteger cost = SDMemoryCacheCostForImage(diskImage); [self.memCache setObject:diskImage forKey:cacheKey cost:cost]; } } @@ -585,7 +431,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { if (fromDisk) { dispatch_async(self.ioQueue, ^{ - [self.fileManager removeItemAtPath:[self cachePathForKey:key] error:nil]; + [self.diskCache removeDataForKey:key]; if (completion) { dispatch_async(dispatch_get_main_queue(), ^{ @@ -593,24 +439,9 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { }); } }); - } else if (completion){ + } else if (completion) { completion(); } - -} - -#pragma mark - KVO - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - if (context == SDImageCacheContext) { - if ([keyPath isEqualToString:NSStringFromSelector(@selector(maxMemoryCost))]) { - self.memCache.totalCostLimit = self.config.maxMemoryCost; - } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(maxMemoryCount))]) { - self.memCache.countLimit = self.config.maxMemoryCount; - } - } else { - [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; - } } #pragma mark - Cache clean Ops @@ -621,12 +452,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { - (void)clearDiskOnCompletion:(nullable SDWebImageNoParamsBlock)completion { dispatch_async(self.ioQueue, ^{ - [self.fileManager removeItemAtPath:self.diskCachePath error:nil]; - [self.fileManager createDirectoryAtPath:self.diskCachePath - withIntermediateDirectories:YES - attributes:nil - error:NULL]; - + [self.diskCache removeAllData]; if (completion) { dispatch_async(dispatch_get_main_queue(), ^{ completion(); @@ -635,81 +461,9 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { }); } -- (void)deleteOldFiles { - [self deleteOldFilesWithCompletionBlock:nil]; -} - - (void)deleteOldFilesWithCompletionBlock:(nullable SDWebImageNoParamsBlock)completionBlock { dispatch_async(self.ioQueue, ^{ - NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES]; - NSArray *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey]; - - // This enumerator prefetches useful properties for our cache files. - NSDirectoryEnumerator *fileEnumerator = [self.fileManager enumeratorAtURL:diskCacheURL - includingPropertiesForKeys:resourceKeys - options:NSDirectoryEnumerationSkipsHiddenFiles - errorHandler:NULL]; - - NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.config.maxCacheAge]; - NSMutableDictionary *> *cacheFiles = [NSMutableDictionary dictionary]; - NSUInteger currentCacheSize = 0; - - // Enumerate all of the files in the cache directory. This loop has two purposes: - // - // 1. Removing files that are older than the expiration date. - // 2. Storing file attributes for the size-based cleanup pass. - NSMutableArray *urlsToDelete = [[NSMutableArray alloc] init]; - for (NSURL *fileURL in fileEnumerator) { - NSError *error; - NSDictionary *resourceValues = [fileURL resourceValuesForKeys:resourceKeys error:&error]; - - // Skip directories and errors. - if (error || !resourceValues || [resourceValues[NSURLIsDirectoryKey] boolValue]) { - continue; - } - - // Remove files that are older than the expiration date; - NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey]; - if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) { - [urlsToDelete addObject:fileURL]; - continue; - } - - // Store a reference to this file and account for its total size. - NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey]; - currentCacheSize += totalAllocatedSize.unsignedIntegerValue; - cacheFiles[fileURL] = resourceValues; - } - - for (NSURL *fileURL in urlsToDelete) { - [self.fileManager removeItemAtURL:fileURL error:nil]; - } - - // If our remaining disk cache exceeds a configured maximum size, perform a second - // size-based cleanup pass. We delete the oldest files first. - if (self.config.maxCacheSize > 0 && currentCacheSize > self.config.maxCacheSize) { - // Target half of our maximum cache size for this cleanup pass. - const NSUInteger desiredCacheSize = self.config.maxCacheSize / 2; - - // Sort the remaining cache files by their last modification time (oldest first). - NSArray *sortedFiles = [cacheFiles keysSortedByValueWithOptions:NSSortConcurrent - usingComparator:^NSComparisonResult(id obj1, id obj2) { - return [obj1[NSURLContentModificationDateKey] compare:obj2[NSURLContentModificationDateKey]]; - }]; - - // Delete files until we fall below our desired cache size. - for (NSURL *fileURL in sortedFiles) { - if ([self.fileManager removeItemAtURL:fileURL error:nil]) { - NSDictionary *resourceValues = cacheFiles[fileURL]; - NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey]; - currentCacheSize -= totalAllocatedSize.unsignedIntegerValue; - - if (currentCacheSize < desiredCacheSize) { - break; - } - } - } - } + [self.diskCache removeExpiredData]; if (completionBlock) { dispatch_async(dispatch_get_main_queue(), ^{ completionBlock(); @@ -718,8 +472,21 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { }); } +#pragma mark - UIApplicationWillTerminateNotification + +#if SD_UIKIT || SD_MAC +- (void)applicationWillTerminate:(NSNotification *)notification { + [self deleteOldFilesWithCompletionBlock:nil]; +} +#endif + +#pragma mark - UIApplicationDidEnterBackgroundNotification + #if SD_UIKIT -- (void)backgroundDeleteOldFiles { +- (void)applicationDidEnterBackground:(NSNotification *)notification { + if (!self.config.shouldRemoveExpiredDataWhenEnterBackground) { + return; + } Class UIApplicationClass = NSClassFromString(@"UIApplication"); if(!UIApplicationClass || ![UIApplicationClass respondsToSelector:@selector(sharedApplication)]) { return; @@ -745,12 +512,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { - (NSUInteger)getSize { __block NSUInteger size = 0; dispatch_sync(self.ioQueue, ^{ - NSDirectoryEnumerator *fileEnumerator = [self.fileManager enumeratorAtPath:self.diskCachePath]; - for (NSString *fileName in fileEnumerator) { - NSString *filePath = [self.diskCachePath stringByAppendingPathComponent:fileName]; - NSDictionary *attrs = [self.fileManager attributesOfItemAtPath:filePath error:nil]; - size += [attrs fileSize]; - } + size = [self.diskCache totalSize]; }); return size; } @@ -758,31 +520,15 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { - (NSUInteger)getDiskCount { __block NSUInteger count = 0; dispatch_sync(self.ioQueue, ^{ - NSDirectoryEnumerator *fileEnumerator = [self.fileManager enumeratorAtPath:self.diskCachePath]; - count = fileEnumerator.allObjects.count; + count = [self.diskCache totalCount]; }); return count; } - (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock { - NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES]; - dispatch_async(self.ioQueue, ^{ - NSUInteger fileCount = 0; - NSUInteger totalSize = 0; - - NSDirectoryEnumerator *fileEnumerator = [self.fileManager enumeratorAtURL:diskCacheURL - includingPropertiesForKeys:@[NSFileSize] - options:NSDirectoryEnumerationSkipsHiddenFiles - errorHandler:NULL]; - - for (NSURL *fileURL in fileEnumerator) { - NSNumber *fileSize; - [fileURL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:NULL]; - totalSize += fileSize.unsignedIntegerValue; - fileCount += 1; - } - + NSUInteger fileCount = [self.diskCache totalCount]; + NSUInteger totalSize = [self.diskCache totalSize]; if (completionBlock) { dispatch_async(dispatch_get_main_queue(), ^{ completionBlock(fileCount, totalSize); diff --git a/SDWebImage/SDImageCacheConfig.h b/SDWebImage/SDImageCacheConfig.h index 471f64c5..188964da 100644 --- a/SDWebImage/SDImageCacheConfig.h +++ b/SDWebImage/SDImageCacheConfig.h @@ -9,7 +9,15 @@ #import #import "SDWebImageCompat.h" -@interface SDImageCacheConfig : NSObject +// This class conform to NSCopying, make sure to add the property in `copyWithZone:` as well. +@interface SDImageCacheConfig : NSObject + +/** + Gets/Sets the default cache config used for shared instance or initialization when it does not provide any cache config. Such as `SDImageCache.sharedImageCache`. + @note You can modify the property on default cache config, which can be used for later created cache instance. The already created cache instance does not get affected. + @note You should not pass nil to this value. + */ +@property (nonatomic, class, nonnull) SDImageCacheConfig *defaultCacheConfig; /** * Whether or not to disable iCloud backup @@ -23,6 +31,12 @@ */ @property (assign, nonatomic) BOOL shouldCacheImagesInMemory; +/** + * Whether or not to remove the expired disk data when application entering the background. (Not works for macOS) + * Defatuls to YES. + */ +@property (assign, nonatomic) BOOL shouldRemoveExpiredDataWhenEnterBackground; + /** * The reading options while reading cache from disk. * Defaults to 0. You can set this to `NSDataReadingMappedIfSafe` to improve performance. @@ -59,4 +73,26 @@ */ @property (assign, nonatomic) NSUInteger maxMemoryCount; +/** + * The custom file manager for disk cache. Pass nil to let disk cache choose the proper file manager. + * Defaults to nil. + * @note This value does not support dynamic changes. Which means further modification on this value after cache initlized has no effect. + * @note Since `NSFileManager` does not support `NSCopying`. We just pass this by reference during copying. So it's not recommend to set this value on `defaultCacheConfig`. + */ +@property (strong, nonatomic, nullable) NSFileManager *fileManager; + +/** + * The custom memory cache class. Provided class instance must conform to `SDMemoryCache` protocol to allow usage. + * Defaults to built-in `SDMemoryCache` class. + * @note This value does not support dynamic changes. Which means further modification on this value after cache initlized has no effect. + */ +@property (assign, nonatomic, nonnull) Class memoryCacheClass; + +/** + * The custom disk cache class. Provided class instance must conform to `SDDiskCache` protocol to allow usage. + * Defaults to built-in `SDDiskCache` class. + * @note This value does not support dynamic changes. Which means further modification on this value after cache initlized has no effect. + */ +@property (assign ,nonatomic, nonnull) Class diskCacheClass; + @end diff --git a/SDWebImage/SDImageCacheConfig.m b/SDWebImage/SDImageCacheConfig.m index ef7f2738..5cb8eedb 100644 --- a/SDWebImage/SDImageCacheConfig.m +++ b/SDWebImage/SDImageCacheConfig.m @@ -7,21 +7,60 @@ */ #import "SDImageCacheConfig.h" +#import "SDMemoryCache.h" +#import "SDDiskCache.h" +static SDImageCacheConfig *_defaultCacheConfig; static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week @implementation SDImageCacheConfig ++ (SDImageCacheConfig *)defaultCacheConfig { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _defaultCacheConfig = [SDImageCacheConfig new]; + }); + return _defaultCacheConfig; +} + ++ (void)setDefaultCacheConfig:(SDImageCacheConfig *)defaultCacheConfig { + if (defaultCacheConfig) { + _defaultCacheConfig = defaultCacheConfig; + } +} + - (instancetype)init { if (self = [super init]) { _shouldDisableiCloud = YES; _shouldCacheImagesInMemory = YES; + _shouldRemoveExpiredDataWhenEnterBackground = YES; _diskCacheReadingOptions = 0; _diskCacheWritingOptions = NSDataWritingAtomic; _maxCacheAge = kDefaultCacheMaxCacheAge; _maxCacheSize = 0; + _memoryCacheClass = [SDMemoryCache class]; + _diskCacheClass = [SDDiskCache class]; } return self; } +- (id)copyWithZone:(NSZone *)zone { + SDImageCacheConfig *config = [[[self class] allocWithZone:zone] init]; + config.shouldDecompressImages = self.shouldDecompressImages; + config.shouldDisableiCloud = self.shouldDisableiCloud; + config.shouldCacheImagesInMemory = self.shouldCacheImagesInMemory; + config.shouldRemoveExpiredDataWhenEnterBackground = self.shouldRemoveExpiredDataWhenEnterBackground; + config.diskCacheReadingOptions = self.diskCacheReadingOptions; + config.diskCacheWritingOptions = self.diskCacheWritingOptions; + config.maxCacheAge = self.maxCacheAge; + config.maxCacheSize = self.maxCacheSize; + config.maxMemoryCost = self.maxMemoryCost; + config.maxMemoryCount = self.maxMemoryCount; + config.fileManager = self.fileManager; // NSFileManager does not conform to NSCopying, just pass the reference + config.memoryCacheClass = self.memoryCacheClass; + config.diskCacheClass = self.diskCacheClass; + + return config; +} + @end diff --git a/SDWebImage/SDMemoryCache.h b/SDWebImage/SDMemoryCache.h new file mode 100644 index 00000000..0fb69150 --- /dev/null +++ b/SDWebImage/SDMemoryCache.h @@ -0,0 +1,81 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +/** + Return the memory cache cost for specify image + + @param image The image to store in cache + @return The memory cost for the image + */ +FOUNDATION_EXPORT NSUInteger SDMemoryCacheCostForImage(UIImage * _Nullable image); + +@class SDImageCacheConfig; +// A protocol to allow custom memory cache used in SDImageCache. +@protocol SDMemoryCache + +@required +/** + Create a new memory cache instance with the specify cache config. You can check `maxMemoryCost` and `maxMemoryCount` used for memory cache. + + @param config The cache config to be used to create the cache. + @return The new memory cache instance. + */ +- (nonnull instancetype)initWithConfig:(nonnull SDImageCacheConfig *)config; + +/** + Returns the value associated with a given key. + + @param key An object identifying the value. If nil, just return nil. + @return The value associated with key, or nil if no value is associated with key. + */ +- (nullable id)objectForKey:(nonnull id)key; + +/** + Sets the value of the specified key in the cache (0 cost). + + @param object The object to be stored in the cache. If nil, it calls `removeObjectForKey:`. + @param key The key with which to associate the value. If nil, this method has no effect. + @discussion Unlike an NSMutableDictionary object, a cache does not copy the key + objects that are put into it. + */ +- (void)setObject:(nullable id)object forKey:(nonnull id)key; + +/** + Sets the value of the specified key in the cache, and associates the key-value + pair with the specified cost. + + @param object The object to store in the cache. If nil, it calls `removeObjectForKey`. + @param key The key with which to associate the value. If nil, this method has no effect. + @param cost The cost with which to associate the key-value pair. + @discussion Unlike an NSMutableDictionary object, a cache does not copy the key + objects that are put into it. + */ +- (void)setObject:(nullable id)object forKey:(nonnull id)key cost:(NSUInteger)cost; + +/** + Removes the value of the specified key in the cache. + + @param key The key identifying the value to be removed. If nil, this method has no effect. + */ +- (void)removeObjectForKey:(nonnull id)key; + +/** + Empties the cache immediately. + */ +- (void)removeAllObjects; + +@end + +// A memory cache which auto purge the cache on memory warning and support weak cache. +@interface SDMemoryCache : NSCache + +@property (nonatomic, strong, nonnull, readonly) SDImageCacheConfig *config; + +@end diff --git a/SDWebImage/SDMemoryCache.m b/SDWebImage/SDMemoryCache.m new file mode 100644 index 00000000..6562185b --- /dev/null +++ b/SDWebImage/SDMemoryCache.m @@ -0,0 +1,150 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDMemoryCache.h" +#import "SDImageCacheConfig.h" + +#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); +#define UNLOCK(lock) dispatch_semaphore_signal(lock); + +NSUInteger SDMemoryCacheCostForImage(UIImage * _Nullable image) { +#if SD_MAC + return image.size.height * image.size.width; +#elif SD_UIKIT || SD_WATCH + return image.size.height * image.size.width * image.scale * image.scale; +#endif +} + +static void * SDMemoryCacheContext = &SDMemoryCacheContext; + +@interface SDMemoryCache () + +@property (nonatomic, strong, nullable) SDImageCacheConfig *config; +@property (nonatomic, strong, nonnull) NSMapTable *weakCache; // strong-weak cache +@property (nonatomic, strong, nonnull) dispatch_semaphore_t weakCacheLock; // a lock to keep the access to `weakCache` thread-safe + +@end + +@implementation SDMemoryCache + +- (void)dealloc { + [_config removeObserver:self forKeyPath:NSStringFromSelector(@selector(maxMemoryCost)) context:SDMemoryCacheContext]; + [_config removeObserver:self forKeyPath:NSStringFromSelector(@selector(maxMemoryCount)) context:SDMemoryCacheContext]; +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +#endif +} + +- (instancetype)init { + self = [super init]; + if (self) { + _config = [[SDImageCacheConfig alloc] init]; + [self commonInit]; + } + return self; +} + +- (instancetype)initWithConfig:(SDImageCacheConfig *)config { + self = [super init]; + if (self) { + _config = config; + [self commonInit]; + } + return self; +} + +- (void)commonInit { + self.weakCache = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory capacity:0]; + self.weakCacheLock = dispatch_semaphore_create(1); + + SDImageCacheConfig *config = self.config; + self.totalCostLimit = config.maxMemoryCost; + self.countLimit = config.maxMemoryCount; + + [config addObserver:self forKeyPath:NSStringFromSelector(@selector(maxMemoryCost)) options:0 context:SDMemoryCacheContext]; + [config addObserver:self forKeyPath:NSStringFromSelector(@selector(maxMemoryCount)) options:0 context:SDMemoryCacheContext]; + +#if SD_UIKIT + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didReceiveMemoryWarning:) + name:UIApplicationDidReceiveMemoryWarningNotification + object:nil]; +#endif +} + +// Current this seems no use on macOS (macOS use virtual memory and do not clear cache when memory warning). So we only override on iOS/tvOS platform. +#if SD_UIKIT +- (void)didReceiveMemoryWarning:(NSNotification *)notification { + // Only remove cache, but keep weak cache + [super removeAllObjects]; +} + +// `setObject:forKey:` just call this with 0 cost. Override this is enough +- (void)setObject:(id)obj forKey:(id)key cost:(NSUInteger)g { + [super setObject:obj forKey:key cost:g]; + if (key && obj) { + // Store weak cache + LOCK(self.weakCacheLock); + [self.weakCache setObject:obj forKey:key]; + UNLOCK(self.weakCacheLock); + } +} + +- (id)objectForKey:(id)key { + id obj = [super objectForKey:key]; + if (key && !obj) { + // Check weak cache + LOCK(self.weakCacheLock); + obj = [self.weakCache objectForKey:key]; + UNLOCK(self.weakCacheLock); + if (obj) { + // Sync cache + NSUInteger cost = 0; + if ([obj isKindOfClass:[UIImage class]]) { + cost = SDMemoryCacheCostForImage(obj); + } + [super setObject:obj forKey:key cost:cost]; + } + } + return obj; +} + +- (void)removeObjectForKey:(id)key { + [super removeObjectForKey:key]; + if (key) { + // Remove weak cache + LOCK(self.weakCacheLock); + [self.weakCache removeObjectForKey:key]; + UNLOCK(self.weakCacheLock); + } +} + +- (void)removeAllObjects { + [super removeAllObjects]; + // Manually remove should also remove weak cache + LOCK(self.weakCacheLock); + [self.weakCache removeAllObjects]; + UNLOCK(self.weakCacheLock); +} +#endif + +#pragma mark - KVO + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if (context == SDMemoryCacheContext) { + if ([keyPath isEqualToString:NSStringFromSelector(@selector(maxMemoryCost))]) { + self.totalCostLimit = self.config.maxMemoryCost; + } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(maxMemoryCount))]) { + self.countLimit = self.config.maxMemoryCount; + } + } else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; + } +} + +@end diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index 948e3adb..2e33b020 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -314,8 +314,10 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; fileManager.mockSelectors = @{NSStringFromSelector(@selector(createDirectoryAtPath:withIntermediateDirectories:attributes:error:)) : targetError}; expect(fileManager.lastError).to.beNil(); + SDImageCacheConfig *config = [SDImageCacheConfig new]; + config.fileManager = fileManager; // This disk cache path creation will be mocked with error. - SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"test" diskCacheDirectory:@"/" fileManager:fileManager]; + SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"test" diskCacheDirectory:@"/" config:config]; [cache storeImageDataToDisk:imageData forKey:kImageTestKey]; expect(fileManager.lastError).equal(targetError); diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index 087c9ca2..c1dd2d5a 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -24,6 +24,8 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import +#import +#import #import #import #import From 2d27300e00f7013bdbdc94aa4a51b5b1548a7d18 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 15 Apr 2018 00:08:08 +0800 Subject: [PATCH 126/361] Add test for custom memory cache and disk cache --- .../project.pbxproj | 8 ++ Tests/Tests/SDImageCacheTests.m | 34 ++++++ Tests/Tests/SDWebImageTestCache.h | 28 +++++ Tests/Tests/SDWebImageTestCache.m | 107 ++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 Tests/Tests/SDWebImageTestCache.h create mode 100644 Tests/Tests/SDWebImageTestCache.m diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 940677b8..d63f6f8f 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -20,6 +20,8 @@ 3264FF30205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */; }; 327054E2206CEFF3006EA328 /* TestImageAnimated.apng in Resources */ = {isa = PBXBuildFile; fileRef = 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */; }; 327054E3206CEFF3006EA328 /* TestImageAnimated.apng in Resources */ = {isa = PBXBuildFile; fileRef = 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */; }; + 328BB6DD20825E9800760D6C /* SDWebImageTestCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6DC20825E9800760D6C /* SDWebImageTestCache.m */; }; + 328BB6DE20825E9800760D6C /* SDWebImageTestCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6DC20825E9800760D6C /* SDWebImageTestCache.m */; }; 32A571562037DB2D002EDAAE /* SDAnimatedImageTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */; }; 32B99E8B203AF8690017FD66 /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */; }; 32B99E9B203B2EDD0017FD66 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; }; @@ -71,6 +73,8 @@ 3264FF2D205D42CB00F6BD48 /* SDWebImageTestTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestTransformer.h; sourceTree = ""; }; 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestTransformer.m; sourceTree = ""; }; 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageAnimated.apng; sourceTree = ""; }; + 328BB6DB20825E9800760D6C /* SDWebImageTestCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestCache.h; sourceTree = ""; }; + 328BB6DC20825E9800760D6C /* SDWebImageTestCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestCache.m; sourceTree = ""; }; 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImageTest.m; sourceTree = ""; }; 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDCategoriesTests.m; sourceTree = ""; }; 32B99E92203B2DF90017FD66 /* Tests Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -210,6 +214,8 @@ 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */, 2D7AF05E1F329763000083C2 /* SDTestCase.h */, 2D7AF05F1F329763000083C2 /* SDTestCase.m */, + 328BB6DB20825E9800760D6C /* SDWebImageTestCache.h */, + 328BB6DC20825E9800760D6C /* SDWebImageTestCache.m */, 3226ECB920754F7700FAFACF /* SDWebImageTestDownloadOperation.h */, 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */, 32E6F0301F3A1B4700A945E6 /* SDWebImageTestDecoder.h */, @@ -465,6 +471,7 @@ files = ( 32B99EAC203B36650017FD66 /* SDWebImageDownloaderTests.m in Sources */, 3254C32120641077008D1022 /* SDWebImageTransformerTests.m in Sources */, + 328BB6DE20825E9800760D6C /* SDWebImageTestCache.m in Sources */, 32B99E9C203B2EE40017FD66 /* SDCategoriesTests.m in Sources */, 32B99EAA203B365F0017FD66 /* SDImageCacheTests.m in Sources */, 32B99EAD203B36690017FD66 /* SDWebImagePrefetcherTests.m in Sources */, @@ -491,6 +498,7 @@ 37D122881EC48B5E00D98CEB /* SDMockFileManager.m in Sources */, 4369C2741D9804B1007E863A /* SDWebCacheCategoriesTests.m in Sources */, 2D7AF0601F329763000083C2 /* SDTestCase.m in Sources */, + 328BB6DD20825E9800760D6C /* SDWebImageTestCache.m in Sources */, 4369C1D11D97F80F007E863A /* SDWebImagePrefetcherTests.m in Sources */, DA248D69195475D800390AB0 /* SDImageCacheTests.m in Sources */, DA248D6B195476AC00390AB0 /* SDWebImageManagerTests.m in Sources */, diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index 2e33b020..35191bd1 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -11,9 +11,17 @@ #import #import "SDWebImageTestDecoder.h" #import "SDMockFileManager.h" +#import "SDWebImageTestCache.h" NSString *kImageTestKey = @"TestImageKey.jpg"; +@interface SDImageCache () + +@property (nonatomic, strong, nonnull) id memCache; +@property (nonatomic, strong, nonnull) id diskCache; + +@end + @interface SDImageCacheTests : SDTestCase @end @@ -323,6 +331,27 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; expect(fileManager.lastError).equal(targetError); } +#pragma mark - SDMemoryCache & SDDiskCache +- (void)test42CustomMemoryCache { + SDImageCacheConfig *config = [[SDImageCacheConfig alloc] init]; + config.memoryCacheClass = [SDWebImageTestMemoryCache class]; + NSString *nameSpace = @"SDWebImageTestMemoryCache"; + NSString *cacheDictionary = [self makeDiskCachePath:nameSpace]; + SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:nameSpace diskCacheDirectory:cacheDictionary config:config]; + SDWebImageTestMemoryCache *memCache = cache.memCache; + expect([memCache isKindOfClass:[SDWebImageTestMemoryCache class]]).to.beTruthy(); +} + +- (void)test43CustomDiskCache { + SDImageCacheConfig *config = [[SDImageCacheConfig alloc] init]; + config.diskCacheClass = [SDWebImageTestDiskCache class]; + NSString *nameSpace = @"SDWebImageTestDiskCache"; + NSString *cacheDictionary = [self makeDiskCachePath:nameSpace]; + SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:nameSpace diskCacheDirectory:cacheDictionary config:config]; + SDWebImageTestDiskCache *diskCache = cache.diskCache; + expect([diskCache isKindOfClass:[SDWebImageTestDiskCache class]]).to.beTruthy(); +} + #pragma mark Helper methods - (UIImage *)imageForTesting{ @@ -339,4 +368,9 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; return [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; } +- (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + return [paths[0] stringByAppendingPathComponent:fullNamespace]; +} + @end diff --git a/Tests/Tests/SDWebImageTestCache.h b/Tests/Tests/SDWebImageTestCache.h new file mode 100644 index 00000000..0736c698 --- /dev/null +++ b/Tests/Tests/SDWebImageTestCache.h @@ -0,0 +1,28 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Matt Galloway + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import + +// A really naive implementation of custom memory cache and disk cache + +@interface SDWebImageTestMemoryCache : NSObject + +@property (nonatomic, strong, nonnull) SDImageCacheConfig *config; +@property (nonatomic, strong, nonnull) NSCache *cache; + +@end + +@interface SDWebImageTestDiskCache : NSObject + +@property (nonatomic, strong, nonnull) SDImageCacheConfig *config; +@property (nonatomic, copy, nonnull) NSString *cachePath; +@property (nonatomic, strong, nonnull) NSFileManager *fileManager; + +@end diff --git a/Tests/Tests/SDWebImageTestCache.m b/Tests/Tests/SDWebImageTestCache.m new file mode 100644 index 00000000..da2a9935 --- /dev/null +++ b/Tests/Tests/SDWebImageTestCache.m @@ -0,0 +1,107 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Matt Galloway + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageTestCache.h" +#import + +@implementation SDWebImageTestMemoryCache + +- (nonnull instancetype)initWithConfig:(nonnull SDImageCacheConfig *)config { + self = [super init]; + if (self) { + self.config = config; + self.cache = [[NSCache alloc] init]; + } + return self; +} + +- (nullable id)objectForKey:(nonnull id)key { + return [self.cache objectForKey:key]; +} + +- (void)removeAllObjects { + [self.cache removeAllObjects]; +} + +- (void)removeObjectForKey:(nonnull id)key { + [self.cache removeObjectForKey:key]; +} + +- (void)setObject:(nullable id)object forKey:(nonnull id)key { + [self.cache setObject:object forKey:key]; +} + +- (void)setObject:(nullable id)object forKey:(nonnull id)key cost:(NSUInteger)cost { + [self.cache setObject:object forKey:key cost:cost]; +} + +@end + +@implementation SDWebImageTestDiskCache + +- (nullable NSString *)cachePathForKey:(nonnull NSString *)key { + return [self.cachePath stringByAppendingPathComponent:key]; +} + +- (BOOL)containsDataForKey:(nonnull NSString *)key { + return [self.fileManager fileExistsAtPath:[self cachePathForKey:key]]; +} + +- (nullable NSData *)dataForKey:(nonnull NSString *)key { + return [self.fileManager contentsAtPath:[self cachePathForKey:key]]; +} + +- (nullable instancetype)initWithCachePath:(nonnull NSString *)cachePath config:(nonnull SDImageCacheConfig *)config { + self = [super init]; + if (self) { + self.cachePath = cachePath; + self.config = config; + self.fileManager = config.fileManager ? config.fileManager : [NSFileManager new]; + [self.fileManager createDirectoryAtPath:self.cachePath withIntermediateDirectories:YES attributes:nil error:nil]; + } + return self; +} + +- (void)removeAllData { + [self.fileManager removeItemAtPath:self.cachePath error:nil]; +} + +- (void)removeDataForKey:(nonnull NSString *)key { + [self.fileManager removeItemAtPath:[self cachePathForKey:key] error:nil]; +} + +- (void)removeExpiredData { + NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.config.maxCacheAge]; + for (NSString *fileName in [self.fileManager enumeratorAtPath:self.cachePath]) { + NSString *filePath = [self.cachePath stringByAppendingPathComponent:fileName]; + NSDate *modificationDate = [[self.fileManager attributesOfItemAtPath:filePath error:nil] objectForKey:NSFileModificationDate]; + if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) { + [self.fileManager removeItemAtPath:filePath error:nil]; + } + } +} + +- (void)setData:(nullable NSData *)data forKey:(nonnull NSString *)key { + [self.fileManager createFileAtPath:[self cachePathForKey:key] contents:data attributes:nil]; +} + +- (NSInteger)totalCount { + return [self.fileManager contentsOfDirectoryAtPath:self.cachePath error:nil].count; +} + +- (NSInteger)totalSize { + NSUInteger size = 0; + for (NSString *fileName in [self.fileManager enumeratorAtPath:self.cachePath]) { + NSString *filePath = [self.cachePath stringByAppendingPathComponent:fileName]; + size += [[[self.fileManager attributesOfItemAtPath:filePath error:nil] objectForKey:NSFileSize] unsignedIntegerValue]; + } + return size; +} + +@end From a8639f9fd0693ee0e2c6eff51f175fc3372f0f78 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 01:35:44 +0800 Subject: [PATCH 127/361] Use `NSTimeInterval` for age property, because it's more proper represent seconds --- SDWebImage/SDImageCacheConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/SDImageCacheConfig.h b/SDWebImage/SDImageCacheConfig.h index 188964da..2590fbbf 100644 --- a/SDWebImage/SDImageCacheConfig.h +++ b/SDWebImage/SDImageCacheConfig.h @@ -53,7 +53,7 @@ * The maximum length of time to keep an image in the cache, in seconds. * Defaults to 1 weak. */ -@property (assign, nonatomic) NSInteger maxCacheAge; +@property (assign, nonatomic) NSTimeInterval maxCacheAge; /** * The maximum size of the cache, in bytes. From 56fea371b0a980b3c3111f09d6de2b1a3d3a74ce Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 11:10:53 +0800 Subject: [PATCH 128/361] Fix compile issue --- SDWebImage/SDImageCacheConfig.m | 1 - 1 file changed, 1 deletion(-) diff --git a/SDWebImage/SDImageCacheConfig.m b/SDWebImage/SDImageCacheConfig.m index 5cb8eedb..2b36ea51 100644 --- a/SDWebImage/SDImageCacheConfig.m +++ b/SDWebImage/SDImageCacheConfig.m @@ -46,7 +46,6 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week - (id)copyWithZone:(NSZone *)zone { SDImageCacheConfig *config = [[[self class] allocWithZone:zone] init]; - config.shouldDecompressImages = self.shouldDecompressImages; config.shouldDisableiCloud = self.shouldDisableiCloud; config.shouldCacheImagesInMemory = self.shouldCacheImagesInMemory; config.shouldRemoveExpiredDataWhenEnterBackground = self.shouldRemoveExpiredDataWhenEnterBackground; From d19311e08cee3bb4d4c6ec9c6f8d3a4620d1ebac Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 11:27:50 +0800 Subject: [PATCH 129/361] Revert "Fix two warnings about losing precision in comparison" This reverts commit a710bc547275bb0311a45b5f356e2313562f764c. --- SDWebImage/SDWebImageDownloaderOperation.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 3c17b2fd..5d0c5d1d 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -46,7 +46,7 @@ typedef NSMutableDictionary SDCallbacksDictionary; @property (strong, nonatomic, nullable) NSMutableData *imageData; @property (copy, nonatomic, nullable) NSData *cachedData; // for `SDWebImageDownloaderIgnoreCachedResponse` @property (copy, nonatomic, nullable) NSString *cacheKey; -@property (assign, nonatomic, readwrite) NSUInteger expectedSize; +@property (assign, nonatomic, readwrite) long long expectedSize; @property (strong, nonatomic, nullable, readwrite) NSURLResponse *response; // This is weak because it is injected by whoever manages this session. If this gets nil-ed out, we won't be able to run @@ -342,7 +342,7 @@ didReceiveResponse:(NSURLResponse *)response // Get the image data __block NSData *imageData = [self.imageData copy]; // Get the total bytes downloaded - const NSUInteger totalSize = imageData.length; + const NSInteger totalSize = imageData.length; // Get the finish status BOOL finished = (totalSize >= self.expectedSize); From dd2e71c99dcb77c5f4e57def791d60b58338a2c7 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 12:03:24 +0800 Subject: [PATCH 130/361] Add support for SDAnimatedImage imageNamed:bundle: for macOS, enable SDAnimatedImageTest for macOS --- SDWebImage/SDAnimatedImage.h | 2 ++ SDWebImage/SDAnimatedImage.m | 6 +++- .../project.pbxproj | 2 ++ Tests/Tests/SDAnimatedImageTest.m | 29 +++++++++++++++++-- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h index bb452669..92282f56 100644 --- a/SDWebImage/SDAnimatedImage.h +++ b/SDWebImage/SDAnimatedImage.h @@ -54,6 +54,8 @@ + (nullable instancetype)imageNamed:(nonnull NSString *)name; // Cache in memory, no Asset Catalog support #if __has_include() + (nullable instancetype)imageNamed:(nonnull NSString *)name inBundle:(nullable NSBundle *)bundle compatibleWithTraitCollection:(nullable UITraitCollection *)traitCollection; // Cache in memory, no Asset Catalog support +#else ++ (nullable instancetype)imageNamed:(nonnull NSString *)name inBundle:(nullable NSBundle *)bundle; // Cache in memory, no Asset Catalog support #endif + (nullable instancetype)imageWithContentsOfFile:(nonnull NSString *)path; + (nullable instancetype)imageWithData:(nonnull NSData *)data; diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index 34d88051..c54dc112 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -212,7 +212,7 @@ static NSArray *SDBundlePreferredScales() { #if __has_include() return [self imageNamed:name inBundle:nil compatibleWithTraitCollection:nil]; #else - return [self imageNamed:name inBundle:nil scale:0]; + return [self imageNamed:name inBundle:nil]; #endif } @@ -224,6 +224,10 @@ static NSArray *SDBundlePreferredScales() { CGFloat scale = traitCollection.displayScale; return [self imageNamed:name inBundle:bundle scale:scale]; } +#else ++ (instancetype)imageNamed:(NSString *)name inBundle:(NSBundle *)bundle { + return [self imageNamed:name inBundle:bundle scale:0]; +} #endif // 0 scale means automatically check diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 940677b8..c34ad2bc 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 0314594336AFF15E5BB7F0E6 /* Pods_Tests_Mac.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C140E5ED8501C2ABBFD97A24 /* Pods_Tests_Mac.framework */; }; 1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */; }; 2D7AF0601F329763000083C2 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; }; + 320630412085A37C006E0FA4 /* SDAnimatedImageTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */; }; 321259EC1F39E3240096FE0E /* TestImageStatic.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259EB1F39E3240096FE0E /* TestImageStatic.webp */; }; 321259EE1F39E4110096FE0E /* TestImageAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */; }; 3226ECBB20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */; }; @@ -474,6 +475,7 @@ 32B99EAB203B36620017FD66 /* SDWebImageManagerTests.m in Sources */, 32B99EA9203B34B60017FD66 /* SDWebImageDecoderTests.m in Sources */, 3264FF30205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */, + 320630412085A37C006E0FA4 /* SDAnimatedImageTest.m in Sources */, 32B99E9B203B2EDD0017FD66 /* SDTestCase.m in Sources */, 3226ECBC20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */, ); diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index add6c40a..0434b948 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -15,6 +15,11 @@ #import #import +#if SD_MAC +#define UIWindow NSWindow +#define UIScreen NSScreen +#endif + static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop count // Internal header @@ -69,7 +74,12 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun } - (void)test04AnimatedImageImageNamed { - SDAnimatedImage *image = [SDAnimatedImage imageNamed:@"TestImage.gif" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil]; + NSBundle *bundle = [NSBundle bundleForClass:[self class]]; +#if SD_UIKIT + SDAnimatedImage *image = [SDAnimatedImage imageNamed:@"TestImage.gif" inBundle:bundle compatibleWithTraitCollection:nil]; +#else + SDAnimatedImage *image = [SDAnimatedImage imageNamed:@"TestImage.gif" inBundle:bundle]; +#endif expect(image).notTo.beNil(); expect([image.animatedImageData isEqualToData:[self testGIFData]]).beTruthy(); } @@ -91,7 +101,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun - (void)test06AnimatedImageViewSetImage { SDAnimatedImageView *imageView = [SDAnimatedImageView new]; - UIImage *image = [UIImage imageWithData:[self testJPEGData]]; + UIImage *image = [[UIImage alloc] initWithData:[self testJPEGData]]; imageView.image = image; expect(imageView.image).notTo.beNil(); expect(imageView.currentFrame).beNil(); // current frame @@ -108,7 +118,11 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun - (void)test08AnimatedImageViewRendering { XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView rendering"]; SDAnimatedImageView *imageView = [[SDAnimatedImageView alloc] init]; +#if SD_UIKIT [self.window addSubview:imageView]; +#else + [self.window.contentView addSubview:imageView]; +#endif NSMutableDictionary *frames = [NSMutableDictionary dictionaryWithCapacity:kTestGIFFrameCount]; @@ -128,7 +142,11 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun loopFinished = YES; } if (framesRendered && loopFinished) { +#if SD_UIKIT [imageView stopAnimating]; +#else + imageView.animates = NO; +#endif [expectation fulfill]; } }]; @@ -205,7 +223,12 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun #pragma mark - Helper - (UIWindow *)window { if (!_window) { - _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + UIScreen *mainScreen = [UIScreen mainScreen]; +#if SD_UIKIT + _window = [[UIWindow alloc] initWithFrame:mainScreen.bounds]; +#else + _window = [[NSWindow alloc] initWithContentRect:mainScreen.frame styleMask:0 backing:NSBackingStoreBuffered defer:NO screen:mainScreen]; +#endif } return _window; } From d9c93e1a86cf64ff1c4940729e5db822e3ad1d9d Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 13:01:10 +0800 Subject: [PATCH 131/361] Revert "Revert "Fix two warnings about losing precision in comparison"" This reverts commit d19311e08cee3bb4d4c6ec9c6f8d3a4620d1ebac. --- SDWebImage/SDWebImageDownloaderOperation.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 5d0c5d1d..3c17b2fd 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -46,7 +46,7 @@ typedef NSMutableDictionary SDCallbacksDictionary; @property (strong, nonatomic, nullable) NSMutableData *imageData; @property (copy, nonatomic, nullable) NSData *cachedData; // for `SDWebImageDownloaderIgnoreCachedResponse` @property (copy, nonatomic, nullable) NSString *cacheKey; -@property (assign, nonatomic, readwrite) long long expectedSize; +@property (assign, nonatomic, readwrite) NSUInteger expectedSize; @property (strong, nonatomic, nullable, readwrite) NSURLResponse *response; // This is weak because it is injected by whoever manages this session. If this gets nil-ed out, we won't be able to run @@ -342,7 +342,7 @@ didReceiveResponse:(NSURLResponse *)response // Get the image data __block NSData *imageData = [self.imageData copy]; // Get the total bytes downloaded - const NSInteger totalSize = imageData.length; + const NSUInteger totalSize = imageData.length; // Get the finish status BOOL finished = (totalSize >= self.expectedSize); From 7cba215b1df2fcf89876318baf1538f68c8b6ac0 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 13:02:07 +0800 Subject: [PATCH 132/361] Fix codecov to use gcov reports instead of llvm-cov --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d2a9bbb1..b13f33c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,4 +54,4 @@ script: - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests Mac' -sdk macosx -destination 'platform=OS X,arch=x86_64' -configuration Debug | xcpretty -c after_success: - - bash <(curl -s https://codecov.io/bash) \ No newline at end of file + - bash <(curl -s https://codecov.io/bash) -X xcode \ No newline at end of file From 27ee8a7ac27c43472e7bc44f545844fdee0be783 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 14:42:11 +0800 Subject: [PATCH 133/361] Update the codecov script to seperate iOS & macOS test coverage --- .travis.yml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index b13f33c4..650242ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,10 @@ script: - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS static' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS static' -sdk watchsimulator -configuration Debug | xcpretty -c + - echo Clean static library + - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS static' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c + - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS static' -sdk watchsimulator -configuration Debug | xcpretty -c + - echo Build as dynamic framework - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX' -sdk macosx -configuration Debug | xcpretty -c - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c @@ -44,14 +48,17 @@ script: - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage TV Demo' -sdk appletvsimulator -configuration Debug | xcpretty -c - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c + - echo Clean dynamic framework + - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX Demo' -sdk macosx -configuration Debug | xcpretty -c + - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c + - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage TV Demo' -sdk appletvsimulator -configuration Debug | xcpretty -c + - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c + - echo Run the tests - pod install --project-directory=Tests - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6s' -configuration Debug | xcpretty -c - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX' -sdk macosx -configuration Debug | xcpretty -c - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX Demo' -sdk macosx -configuration Debug | xcpretty -c - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests Mac' -sdk macosx -destination 'platform=OS X,arch=x86_64' -configuration Debug | xcpretty -c after_success: - - bash <(curl -s https://codecov.io/bash) -X xcode \ No newline at end of file + - bash <(curl -s https://codecov.io/bash) -J '^Tests$' -F 'iOS' + - bash <(curl -s https://codecov.io/bash) -J '^Tests Mac$' -F 'macOS' \ No newline at end of file From 62871306cef0037aa158228a4f3ee186a21ef346 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 16:15:19 +0800 Subject: [PATCH 134/361] Ignore the vendor and test folder, only calculate iOS test coverage (merge macOS will wrong result) --- .travis.yml | 14 ++++++++++---- codecov.yml | 5 +++++ 2 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 codecov.yml diff --git a/.travis.yml b/.travis.yml index 650242ba..06950a69 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,17 +48,23 @@ script: - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage TV Demo' -sdk appletvsimulator -configuration Debug | xcpretty -c - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c - - echo Clean dynamic framework + - echo Clean the Demo apps - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX Demo' -sdk macosx -configuration Debug | xcpretty -c - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage TV Demo' -sdk appletvsimulator -configuration Debug | xcpretty -c - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c + - echo Clean dynamic framework + - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX' -sdk macosx -configuration Debug | xcpretty -c + - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c + - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage tvOS' -sdk appletvsimulator -configuration Debug | xcpretty -c + - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS' -sdk watchsimulator -configuration Debug | xcpretty -c + - echo Run the tests - pod install --project-directory=Tests - - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6s' -configuration Debug | xcpretty -c - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests Mac' -sdk macosx -destination 'platform=OS X,arch=x86_64' -configuration Debug | xcpretty -c + - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'Tests Mac' -sdk macosx -destination 'platform=OS X,arch=x86_64' -configuration Debug | xcpretty -c + - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6s' -configuration Debug | xcpretty -c after_success: - - bash <(curl -s https://codecov.io/bash) -J '^Tests$' -F 'iOS' - - bash <(curl -s https://codecov.io/bash) -J '^Tests Mac$' -F 'macOS' \ No newline at end of file + - bash <(curl -s https://codecov.io/bash) -J '^SDWebImage$' \ No newline at end of file diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..6b7ba900 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,5 @@ +coverage: + ignore: + - "Examples" + - "Vendors" + - "Tests" \ No newline at end of file From f0868ccfe8009fe2da19edc40c2270c121154fe9 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 16:57:05 +0800 Subject: [PATCH 135/361] Still fix the codecov issue by Clean all DerivedData before the test --- .travis.yml | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/.travis.yml b/.travis.yml index 06950a69..4eea3056 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,18 +29,14 @@ script: - pod lib lint --allow-warnings - echo Build as static library - - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS static' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c - - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS static' -sdk watchsimulator -configuration Debug | xcpretty -c - - - echo Clean static library - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS static' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS static' -sdk watchsimulator -configuration Debug | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS static' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS static' -sdk watchsimulator -configuration Debug | xcpretty -c - echo Build as dynamic framework - - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX' -sdk macosx -configuration Debug | xcpretty -c - - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c - - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage tvOS' -sdk appletvsimulator -configuration Debug | xcpretty -c - - xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS' -sdk watchsimulator -configuration Debug | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX' -sdk macosx -configuration Debug | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage tvOS' -sdk appletvsimulator -configuration Debug | xcpretty -c + - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS' -sdk watchsimulator -configuration Debug | xcpretty -c - echo Build the Demo apps - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX Demo' -sdk macosx -configuration Debug | xcpretty -c @@ -48,17 +44,8 @@ script: - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage TV Demo' -sdk appletvsimulator -configuration Debug | xcpretty -c - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c - - echo Clean the Demo apps - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX Demo' -sdk macosx -configuration Debug | xcpretty -c - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage TV Demo' -sdk appletvsimulator -configuration Debug | xcpretty -c - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c - - - echo Clean dynamic framework - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX' -sdk macosx -configuration Debug | xcpretty -c - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage tvOS' -sdk appletvsimulator -configuration Debug | xcpretty -c - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS' -sdk watchsimulator -configuration Debug | xcpretty -c + - echo Clean all DerivedData + - rm -rf ~/Library/Developer/Xcode/DerivedData/* - echo Run the tests - pod install --project-directory=Tests From cb7d5288c3422a9cb4e0d5767734e6f653f1af6c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 17:54:31 +0800 Subject: [PATCH 136/361] Save the DerivedData folder for iOS & macOS test finished, only upload the correct test --- .travis.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4eea3056..2c9ed21d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,14 +44,17 @@ script: - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage TV Demo' -sdk appletvsimulator -configuration Debug | xcpretty -c - xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c - - echo Clean all DerivedData - - rm -rf ~/Library/Developer/Xcode/DerivedData/* + - echo Clean DerivedData + - mkdir DerivedData + - rm -rf ~/Library/Developer/Xcode/DerivedData - echo Run the tests - pod install --project-directory=Tests - - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests Mac' -sdk macosx -destination 'platform=OS X,arch=x86_64' -configuration Debug | xcpretty -c - - xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'Tests Mac' -sdk macosx -destination 'platform=OS X,arch=x86_64' -configuration Debug | xcpretty -c - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6s' -configuration Debug | xcpretty -c + - mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/iOS + - xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests Mac' -sdk macosx -destination 'platform=OS X,arch=x86_64' -configuration Debug | xcpretty -c + - mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/macOS after_success: - - bash <(curl -s https://codecov.io/bash) -J '^SDWebImage$' \ No newline at end of file + - bash <(curl -s https://codecov.io/bash) -D './DerivedData/iOS' -J '^SDWebImage$' -F 'iOS' + - bash <(curl -s https://codecov.io/bash) -D './DerivedData/macOS' -J '^SDWebImage$' -F 'macOS' From 77426d127f405d2be960ad714fbf87ca371b0ccc Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 19:28:41 +0800 Subject: [PATCH 137/361] Fix the default download config & cache config to readonly. You can modify the property of config, but not the override the default config instance itself. --- SDWebImage/SDImageCacheConfig.h | 5 ++--- SDWebImage/SDImageCacheConfig.m | 6 ------ SDWebImage/SDWebImageDownloaderConfig.h | 5 ++--- SDWebImage/SDWebImageDownloaderConfig.m | 6 ------ 4 files changed, 4 insertions(+), 18 deletions(-) diff --git a/SDWebImage/SDImageCacheConfig.h b/SDWebImage/SDImageCacheConfig.h index 2590fbbf..2d2e28ee 100644 --- a/SDWebImage/SDImageCacheConfig.h +++ b/SDWebImage/SDImageCacheConfig.h @@ -13,11 +13,10 @@ @interface SDImageCacheConfig : NSObject /** - Gets/Sets the default cache config used for shared instance or initialization when it does not provide any cache config. Such as `SDImageCache.sharedImageCache`. + Gets the default cache config used for shared instance or initialization when it does not provide any cache config. Such as `SDImageCache.sharedImageCache`. @note You can modify the property on default cache config, which can be used for later created cache instance. The already created cache instance does not get affected. - @note You should not pass nil to this value. */ -@property (nonatomic, class, nonnull) SDImageCacheConfig *defaultCacheConfig; +@property (nonatomic, class, readonly, nonnull) SDImageCacheConfig *defaultCacheConfig; /** * Whether or not to disable iCloud backup diff --git a/SDWebImage/SDImageCacheConfig.m b/SDWebImage/SDImageCacheConfig.m index 2b36ea51..71110ae6 100644 --- a/SDWebImage/SDImageCacheConfig.m +++ b/SDWebImage/SDImageCacheConfig.m @@ -23,12 +23,6 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week return _defaultCacheConfig; } -+ (void)setDefaultCacheConfig:(SDImageCacheConfig *)defaultCacheConfig { - if (defaultCacheConfig) { - _defaultCacheConfig = defaultCacheConfig; - } -} - - (instancetype)init { if (self = [super init]) { _shouldDisableiCloud = YES; diff --git a/SDWebImage/SDWebImageDownloaderConfig.h b/SDWebImage/SDWebImageDownloaderConfig.h index 8caf8d95..ca41767b 100644 --- a/SDWebImage/SDWebImageDownloaderConfig.h +++ b/SDWebImage/SDWebImageDownloaderConfig.h @@ -24,11 +24,10 @@ typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { @interface SDWebImageDownloaderConfig : NSObject /** - Gets/Sets the default downloader config used for shared instance or initialization when it does not provide any downloader config. Such as `SDWebImageDownloader.sharedDownloader`. + Gets the default downloader config used for shared instance or initialization when it does not provide any downloader config. Such as `SDWebImageDownloader.sharedDownloader`. @note You can modify the property on default downloader config, which can be used for later created downloader instance. The already created downloader instance does not get affected. - @note You should not pass nil to this value. */ -@property (nonatomic, class, nonnull) SDWebImageDownloaderConfig *defaultDownloaderConfig; +@property (nonatomic, class, readonly, nonnull) SDWebImageDownloaderConfig *defaultDownloaderConfig; /** * The maximum number of concurrent downloads. diff --git a/SDWebImage/SDWebImageDownloaderConfig.m b/SDWebImage/SDWebImageDownloaderConfig.m index 869dbf1c..393d6e06 100644 --- a/SDWebImage/SDWebImageDownloaderConfig.m +++ b/SDWebImage/SDWebImageDownloaderConfig.m @@ -20,12 +20,6 @@ static SDWebImageDownloaderConfig * _defaultDownloaderConfig; return _defaultDownloaderConfig; } -+ (void)setDefaultDownloaderConfig:(SDWebImageDownloaderConfig *)defaultDownloaderConfig { - if (defaultDownloaderConfig) { - _defaultDownloaderConfig = defaultDownloaderConfig; - } -} - - (instancetype)init { self = [super init]; if (self) { From 60d58ef9771d6a970b34226bc1939af6ae4355a6 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 18 Apr 2018 12:50:05 +0800 Subject: [PATCH 138/361] Refactor all current custom error in SDWebImageErrorDomain with error code. Also using NS_ERROR_ENUM to provide better Swift API --- SDWebImage.xcodeproj/project.pbxproj | 28 ++++++++++++++++++++++ SDWebImage/SDWebImageCompat.h | 2 -- SDWebImage/SDWebImageCompat.m | 2 -- SDWebImage/SDWebImageDownloader.m | 5 ++-- SDWebImage/SDWebImageDownloaderOperation.m | 3 ++- SDWebImage/SDWebImageError.h | 18 ++++++++++++++ SDWebImage/SDWebImageError.m | 12 ++++++++++ SDWebImage/SDWebImageManager.m | 3 ++- SDWebImage/UIView+WebCache.m | 3 ++- WebImage/SDWebImage.h | 1 + 10 files changed, 68 insertions(+), 9 deletions(-) create mode 100644 SDWebImage/SDWebImageError.h create mode 100644 SDWebImage/SDWebImageError.m diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 8b067e34..ef5a517d 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -39,6 +39,18 @@ 00733A731BC4880E00A5A117 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 320224BB203979BA00E9F285 /* SDAnimatedImageRep.h in Headers */ = {isa = PBXBuildFile; fileRef = 320224B9203979BA00E9F285 /* SDAnimatedImageRep.h */; settings = {ATTRIBUTES = (Public, ); }; }; 320224BC203979BA00E9F285 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; + 320CAE152086F50500CFFC80 /* SDWebImageError.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CAE132086F50500CFFC80 /* SDWebImageError.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 320CAE162086F50500CFFC80 /* SDWebImageError.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CAE132086F50500CFFC80 /* SDWebImageError.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 320CAE172086F50500CFFC80 /* SDWebImageError.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CAE132086F50500CFFC80 /* SDWebImageError.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 320CAE182086F50500CFFC80 /* SDWebImageError.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CAE132086F50500CFFC80 /* SDWebImageError.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 320CAE192086F50500CFFC80 /* SDWebImageError.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CAE132086F50500CFFC80 /* SDWebImageError.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 320CAE1A2086F50500CFFC80 /* SDWebImageError.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CAE132086F50500CFFC80 /* SDWebImageError.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 320CAE1B2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; + 320CAE1C2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; + 320CAE1D2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; + 320CAE1E2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; + 320CAE1F2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; + 320CAE202086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; 321DB3612011D4D70015D2CB /* NSButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321DB3622011D4D70015D2CB /* NSButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */; }; 321E60861F38E8C800405457 /* SDWebImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDWebImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1481,6 +1493,8 @@ 00733A4C1BC487C000A5A117 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 320224B9203979BA00E9F285 /* SDAnimatedImageRep.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDAnimatedImageRep.h; sourceTree = ""; }; 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImageRep.m; sourceTree = ""; }; + 320CAE132086F50500CFFC80 /* SDWebImageError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageError.h; sourceTree = ""; }; + 320CAE142086F50500CFFC80 /* SDWebImageError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageError.m; sourceTree = ""; }; 321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSButton+WebCache.h"; path = "SDWebImage/NSButton+WebCache.h"; sourceTree = ""; }; 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSButton+WebCache.m"; path = "SDWebImage/NSButton+WebCache.m"; sourceTree = ""; }; 321E60841F38E8C800405457 /* SDWebImageCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoder.h; sourceTree = ""; }; @@ -2100,6 +2114,8 @@ children = ( 53922D88148C56230056699D /* SDWebImageCompat.h */, 5340674F167780C40042B59E /* SDWebImageCompat.m */, + 320CAE132086F50500CFFC80 /* SDWebImageError.h */, + 320CAE142086F50500CFFC80 /* SDWebImageError.m */, 530E49E71646388E002868E7 /* SDWebImageOperation.h */, 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */, 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */, @@ -2320,6 +2336,7 @@ 431739591CDFC8B70008FEB9 /* mux.h in Headers */, 00733A6C1BC4880E00A5A117 /* UIButton+WebCache.h in Headers */, 80377DB01F2F66A700F89830 /* common_sse2.h in Headers */, + 320CAE182086F50500CFFC80 /* SDWebImageError.h in Headers */, 80377DDB1F2F66A700F89830 /* msa_macro.h in Headers */, 4317395B1CDFC8B70008FEB9 /* types.h in Headers */, 80377C531F2F666300F89830 /* huffman_utils.h in Headers */, @@ -2416,6 +2433,7 @@ 4314D1701D0E0E3B004B36C9 /* mux.h in Headers */, 321E60871F38E8C800405457 /* SDWebImageCoder.h in Headers */, 80377EA21F2F66D400F89830 /* vp8i_dec.h in Headers */, + 320CAE162086F50500CFFC80 /* SDWebImageError.h in Headers */, 3248476A201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 321E60951F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, 80377C211F2F666300F89830 /* quant_levels_dec_utils.h in Headers */, @@ -2545,6 +2563,7 @@ 43A62A1E1D0E0A800089D7DD /* format_constants.h in Headers */, 80377E111F2F66A800F89830 /* lossless_common.h in Headers */, 431BB6F61D06D2C1006A3455 /* UIImage+MultiFormat.h in Headers */, + 320CAE192086F50500CFFC80 /* SDWebImageError.h in Headers */, 32F21B5520788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 807A122C1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, 323F8BFA1F38EF770092B609 /* animi.h in Headers */, @@ -2599,6 +2618,7 @@ 4397D2CB1D0DDD8C00BB2784 /* UIImageView+HighlightedWebCache.h in Headers */, 4397D2CC1D0DDD8C00BB2784 /* mux.h in Headers */, 80377C911F2F666400F89830 /* thread_utils.h in Headers */, + 320CAE1A2086F50500CFFC80 /* SDWebImageError.h in Headers */, 4397D2D01D0DDD8C00BB2784 /* SDWebImageDownloaderOperation.h in Headers */, 4397D2D11D0DDD8C00BB2784 /* decode.h in Headers */, 80377E481F2F66A800F89830 /* dsp.h in Headers */, @@ -2695,6 +2715,7 @@ 4A2CAE1F1AB4BB6C00B6BC39 /* SDImageCache.h in Headers */, 4A2CAE351AB4BB7500B6BC39 /* UIImageView+WebCache.h in Headers */, 80377D6B1F2F66A700F89830 /* common_sse2.h in Headers */, + 320CAE172086F50500CFFC80 /* SDWebImageError.h in Headers */, 4A2CAE181AB4BB6400B6BC39 /* SDWebImageCompat.h in Headers */, 80377D961F2F66A700F89830 /* msa_macro.h in Headers */, 43CE75D11CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */, @@ -2826,6 +2847,7 @@ 323F8B621F38EF770092B609 /* cost_enc.h in Headers */, 43CE75761CFE9427006C64D0 /* FLAnimatedImage.h in Headers */, 323F8BE41F38EF770092B609 /* vp8li_enc.h in Headers */, + 320CAE152086F50500CFFC80 /* SDWebImageError.h in Headers */, 323F8B861F38EF770092B609 /* histogram_enc.h in Headers */, 323F8BF61F38EF770092B609 /* animi.h in Headers */, 321E60861F38E8C800405457 /* SDWebImageCoder.h in Headers */, @@ -3090,6 +3112,7 @@ 80377DC01F2F66A700F89830 /* enc_mips_dsp_r2.c in Sources */, 80377DA91F2F66A700F89830 /* alpha_processing_neon.c in Sources */, 43CE75D51CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */, + 320CAE1E2086F50500CFFC80 /* SDWebImageError.m in Sources */, 80377DB71F2F66A700F89830 /* dec_mips_dsp_r2.c in Sources */, 80377DC31F2F66A700F89830 /* enc_neon.c in Sources */, 80377C501F2F666300F89830 /* huffman_encode_utils.c in Sources */, @@ -3299,6 +3322,7 @@ 80377D2A1F2F66A700F89830 /* cost.c in Sources */, 80377D411F2F66A700F89830 /* filters.c in Sources */, 80377D221F2F66A700F89830 /* alpha_processing.c in Sources */, + 320CAE1C2086F50500CFFC80 /* SDWebImageError.m in Sources */, 80377D391F2F66A700F89830 /* enc_neon.c in Sources */, 80377D5B1F2F66A700F89830 /* upsampling_neon.c in Sources */, 80377D5F1F2F66A700F89830 /* yuv_mips32.c in Sources */, @@ -3460,6 +3484,7 @@ 80377DF91F2F66A800F89830 /* cost.c in Sources */, 80377E101F2F66A800F89830 /* filters.c in Sources */, 80377DF11F2F66A800F89830 /* alpha_processing.c in Sources */, + 320CAE1F2086F50500CFFC80 /* SDWebImageError.m in Sources */, 80377E081F2F66A800F89830 /* enc_neon.c in Sources */, 80377E2A1F2F66A800F89830 /* upsampling_neon.c in Sources */, 80377E2E1F2F66A800F89830 /* yuv_mips32.c in Sources */, @@ -3581,6 +3606,7 @@ 328BB6CC2082581100760D6C /* SDDiskCache.m in Sources */, 323F8C0D1F38EF770092B609 /* muxedit.c in Sources */, 323F8B491F38EF770092B609 /* analysis_enc.c in Sources */, + 320CAE202086F50500CFFC80 /* SDWebImageError.m in Sources */, 80377E6E1F2F66A800F89830 /* upsampling_msa.c in Sources */, 323F8B911F38EF770092B609 /* iterator_enc.c in Sources */, 3290FA0F1FA478AF0047D20C /* SDWebImageFrame.m in Sources */, @@ -3740,6 +3766,7 @@ 80377D641F2F66A700F89830 /* alpha_processing_neon.c in Sources */, 80377C361F2F666300F89830 /* huffman_encode_utils.c in Sources */, 80377D721F2F66A700F89830 /* dec_mips_dsp_r2.c in Sources */, + 320CAE1D2086F50500CFFC80 /* SDWebImageError.m in Sources */, 80377D7E1F2F66A700F89830 /* enc_neon.c in Sources */, 4A2CAE321AB4BB7500B6BC39 /* UIImage+WebP.m in Sources */, 80377DA01F2F66A700F89830 /* upsampling_neon.c in Sources */, @@ -3905,6 +3932,7 @@ 80377CDA1F2F66A100F89830 /* alpha_processing_neon.c in Sources */, 80377C021F2F665300F89830 /* huffman_encode_utils.c in Sources */, 80377CE81F2F66A100F89830 /* dec_mips_dsp_r2.c in Sources */, + 320CAE1B2086F50500CFFC80 /* SDWebImageError.m in Sources */, 80377CF41F2F66A100F89830 /* enc_neon.c in Sources */, 80377D161F2F66A100F89830 /* upsampling_neon.c in Sources */, 80377CDF1F2F66A100F89830 /* argb_sse2.c in Sources */, diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index 3e745113..8a327c8d 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -83,8 +83,6 @@ #define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type #endif -FOUNDATION_EXPORT NSString *const _Nonnull SDWebImageErrorDomain; - #ifndef dispatch_queue_async_safe #define dispatch_queue_async_safe(queue, block)\ if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(queue)) == 0) {\ diff --git a/SDWebImage/SDWebImageCompat.m b/SDWebImage/SDWebImageCompat.m index 2997cfb6..12974010 100644 --- a/SDWebImage/SDWebImageCompat.m +++ b/SDWebImage/SDWebImageCompat.m @@ -15,5 +15,3 @@ #if !OS_OBJECT_USE_OBJC #error SDWebImage need ARC for dispatch object #endif - -NSString *const SDWebImageErrorDomain = @"SDWebImageErrorDomain"; diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 4f356410..1c47878d 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -9,6 +9,7 @@ #import "SDWebImageDownloader.h" #import "SDWebImageDownloaderConfig.h" #import "SDWebImageDownloaderOperation.h" +#import "SDWebImageError.h" static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; @@ -244,7 +245,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; // The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data. if (url == nil) { if (completedBlock) { - NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to download a nil url"}]; + NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidURL userInfo:@{NSLocalizedDescriptionKey : @"Image url is nil"}]; completedBlock(nil, nil, error, YES); } return nil; @@ -257,7 +258,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; if (!operation) { UNLOCK(self.operationsLock); if (completedBlock) { - NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Downloader operation is nil"}]; + NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidDownloadOperation userInfo:@{NSLocalizedDescriptionKey : @"Downloader operation is nil"}]; completedBlock(nil, nil, error, YES); } return nil; diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 3c17b2fd..511cf8e2 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -13,6 +13,7 @@ #import "SDWebImageCodersManager.h" #import "SDWebImageCoderHelper.h" #import "SDAnimatedImage.h" +#import "SDWebImageError.h" #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); #define UNLOCK(lock) dispatch_semaphore_signal(lock); @@ -216,7 +217,7 @@ typedef NSMutableDictionary SDCallbacksDictionary; [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:weakSelf]; }); } else { - [self callCompletionBlocksWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorUnknown userInfo:@{NSLocalizedDescriptionKey : @"Task can't be initialized"}]]; + [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidDownloadOperation userInfo:@{NSLocalizedDescriptionKey : @"Task can't be initialized"}]]; [self done]; return; } diff --git a/SDWebImage/SDWebImageError.h b/SDWebImage/SDWebImageError.h new file mode 100644 index 00000000..50929e90 --- /dev/null +++ b/SDWebImage/SDWebImageError.h @@ -0,0 +1,18 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Jamie Pinkham + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +FOUNDATION_EXPORT NSErrorDomain const _Nonnull SDWebImageErrorDomain; + +typedef NS_ERROR_ENUM(SDWebImageErrorDomain, SDWebImageError) { + SDWebImageErrorInvalidURL = 1000, // The URL is invalid, such as nil URL or corrupted URL + SDWebImageErrorBadImageData = 1001, // The image data can not be decoded to image, or the image data is empty + SDWebImageErrorInvalidDownloadOperation = 2000, // The image download operation is invalid, such as nil operation or unexpected error occur when operation initialized +}; diff --git a/SDWebImage/SDWebImageError.m b/SDWebImage/SDWebImageError.m new file mode 100644 index 00000000..ba154c5a --- /dev/null +++ b/SDWebImage/SDWebImageError.m @@ -0,0 +1,12 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Jamie Pinkham + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageError.h" + +NSErrorDomain const _Nonnull SDWebImageErrorDomain = @"SDWebImageErrorDomain"; diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index bf9cc0e5..3c2e6733 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -10,6 +10,7 @@ #import "NSImage+Additions.h" #import "UIImage+WebCache.h" #import "SDAnimatedImage.h" +#import "SDWebImageError.h" @interface SDWebImageCombinedOperation () @@ -146,7 +147,7 @@ } if (url.absoluteString.length == 0 || (!(options & SDWebImageRetryFailed) && isFailedUrl)) { - [self callCompletionBlockForOperation:operation completion:completedBlock error:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil] url:url]; + [self callCompletionBlockForOperation:operation completion:completedBlock error:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidURL userInfo:@{NSLocalizedDescriptionKey : @"Image url is nil"}] url:url]; return operation; } diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 59666b6b..2f5bc03f 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -12,6 +12,7 @@ #import "objc/runtime.h" #import "UIView+WebCacheOperation.h" +#import "SDWebImageError.h" const int64_t SDWebImageProgressUnitCountUnknown = 1LL; @@ -178,7 +179,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; [self sd_stopImageIndicator]; dispatch_main_async_safe(^{ if (completedBlock) { - NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; + NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidURL userInfo:@{NSLocalizedDescriptionKey : @"Image url is nil"}]; completedBlock(nil, nil, error, SDImageCacheTypeNone, YES, url); } }); diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index 2f57ac06..d063266c 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -66,6 +66,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import +#import #if SD_MAC #import From 9f770b6c193df438cded37016d9aacd7e6819a68 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 13 Apr 2018 18:52:46 +0800 Subject: [PATCH 139/361] Refactor to support custom image cache used for web manager. Supports caches manager with multiple caches and op policy --- .../SDWebImage Demo/MasterViewController.m | 3 +- SDWebImage.xcodeproj/project.pbxproj | 56 ++ SDWebImage/SDImageCache.h | 23 +- SDWebImage/SDImageCache.m | 164 ++++- SDWebImage/SDWebImageCache.h | 109 ++++ SDWebImage/SDWebImageCache.m | 9 + SDWebImage/SDWebImageCachesManager.h | 77 +++ SDWebImage/SDWebImageCachesManager.m | 582 ++++++++++++++++++ SDWebImage/SDWebImageManager.h | 53 +- SDWebImage/SDWebImageManager.m | 102 ++- WebImage/SDWebImage.h | 2 + 11 files changed, 1065 insertions(+), 115 deletions(-) create mode 100644 SDWebImage/SDWebImageCache.h create mode 100644 SDWebImage/SDWebImageCache.m create mode 100644 SDWebImage/SDWebImageCachesManager.h create mode 100644 SDWebImage/SDWebImageCachesManager.m diff --git a/Examples/SDWebImage Demo/MasterViewController.m b/Examples/SDWebImage Demo/MasterViewController.m index 58469d2a..8ead3031 100644 --- a/Examples/SDWebImage Demo/MasterViewController.m +++ b/Examples/SDWebImage Demo/MasterViewController.m @@ -85,8 +85,7 @@ - (void)flushCache { - [SDWebImageManager.sharedManager.imageCache clearMemory]; - [SDWebImageManager.sharedManager.imageCache clearDiskOnCompletion:nil]; + [SDWebImageManager.sharedManager.imageCache clearWithCacheType:SDImageCacheTypeAll completion:nil]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 8b067e34..7a367417 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -496,6 +496,30 @@ 32CF1C101FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; 32CF1C111FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; 32CF1C121FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; + 32D1221E2080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D1221F2080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122202080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122212080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122222080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122232080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122242080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; + 32D122252080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; + 32D122262080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; + 32D122272080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; + 32D122282080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; + 32D122292080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; + 32D1222A2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; }; + 32D1222B2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; }; + 32D1222C2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; }; + 32D1222D2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; }; + 32D1222E2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; }; + 32D1222F2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; }; + 32D122302080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122312080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122322080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122332080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122342080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122352080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32EB6D8E206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; 32EB6D8F206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; 32EB6D90206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; @@ -1558,6 +1582,10 @@ 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageIndicator.m; sourceTree = ""; }; 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoderHelper.h; sourceTree = ""; }; 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCoderHelper.m; sourceTree = ""; }; + 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageCache.h; sourceTree = ""; }; + 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCache.m; sourceTree = ""; }; + 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCachesManager.m; sourceTree = ""; }; + 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageCachesManager.h; sourceTree = ""; }; 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderRequestModifier.h; sourceTree = ""; }; 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderRequestModifier.m; sourceTree = ""; }; 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTransformer.h; sourceTree = ""; }; @@ -2076,6 +2104,10 @@ 328BB6C02082581100760D6C /* SDMemoryCache.m */, 328BB6BD2082581100760D6C /* SDDiskCache.h */, 328BB6BE2082581100760D6C /* SDDiskCache.m */, + 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */, + 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */, + 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */, + 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */, ); name = Cache; sourceTree = ""; @@ -2294,6 +2326,7 @@ 323F8B531F38EF770092B609 /* backward_references_enc.h in Headers */, 4317395A1CDFC8B70008FEB9 /* mux_types.h in Headers */, 431739561CDFC8B70008FEB9 /* demux.h in Headers */, + 32D122212080B2EB003685A3 /* SDWebImageCache.h in Headers */, 32B9B53A206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AD2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 80377C4A1F2F666300F89830 /* bit_writer_utils.h in Headers */, @@ -2362,6 +2395,7 @@ 3248476C201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 80377C5F1F2F666300F89830 /* utils.h in Headers */, 80377C5B1F2F666300F89830 /* rescaler_utils.h in Headers */, + 32D122332080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */, 323F8BF91F38EF770092B609 /* animi.h in Headers */, 32F7C0872030719600873181 /* UIImage+Transform.h in Headers */, 80377C4F1F2F666300F89830 /* filters_utils.h in Headers */, @@ -2389,6 +2423,7 @@ 80377C1D1F2F666300F89830 /* huffman_encode_utils.h in Headers */, 321E60B11F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 80377E9A1F2F66D400F89830 /* common_dec.h in Headers */, + 32D1221F2080B2EB003685A3 /* SDWebImageCache.h in Headers */, 327054D5206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, 328BB6AB2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 32B9B538206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, @@ -2429,6 +2464,7 @@ 80377C271F2F666300F89830 /* rescaler_utils.h in Headers */, 323F8B511F38EF770092B609 /* backward_references_enc.h in Headers */, 325312C9200F09910046BF1E /* SDWebImageTransition.h in Headers */, + 32D122312080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */, 43A918651D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 4314D1741D0E0E3B004B36C9 /* types.h in Headers */, 4314D1761D0E0E3B004B36C9 /* decode.h in Headers */, @@ -2510,6 +2546,7 @@ 80377E211F2F66A800F89830 /* neon.h in Headers */, 80377C711F2F666400F89830 /* quant_levels_utils.h in Headers */, 323F8B541F38EF770092B609 /* backward_references_enc.h in Headers */, + 32D122342080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */, 32F7C0882030719600873181 /* UIImage+Transform.h in Headers */, 43A62A1F1D0E0A800089D7DD /* mux.h in Headers */, 431BB6E91D06D2C1006A3455 /* SDWebImageDownloaderOperation.h in Headers */, @@ -2553,6 +2590,7 @@ 32F7C0732030114C00873181 /* SDWebImageTransformer.h in Headers */, 431BB6FA1D06D2C1006A3455 /* SDWebImageDownloader.h in Headers */, 3248476D201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, + 32D122222080B2EB003685A3 /* SDWebImageCache.h in Headers */, 80377DF51F2F66A800F89830 /* common_sse2.h in Headers */, 323F8BDC1F38EF770092B609 /* vp8i_enc.h in Headers */, 80377ED21F2F66D500F89830 /* vp8i_dec.h in Headers */, @@ -2573,6 +2611,7 @@ 32F7C0892030719600873181 /* UIImage+Transform.h in Headers */, 80377EDA1F2F66D500F89830 /* common_dec.h in Headers */, 80377EE61F2F66D500F89830 /* webpi_dec.h in Headers */, + 32D122232080B2EB003685A3 /* SDWebImageCache.h in Headers */, 32B9B53C206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AF2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 4397D2BA1D0DDD8C00BB2784 /* demux.h in Headers */, @@ -2641,6 +2680,7 @@ 321E608B1F38E8C800405457 /* SDWebImageCoder.h in Headers */, 323F8B731F38EF770092B609 /* delta_palettization_enc.h in Headers */, 321E60C31F38E91700405457 /* UIImage+ForceDecode.h in Headers */, + 32D122352080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */, 32484768201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80377E561F2F66A800F89830 /* lossless_common.h in Headers */, 4397D2E91D0DDD8C00BB2784 /* UIImage+WebP.h in Headers */, @@ -2669,6 +2709,7 @@ 323F8B521F38EF770092B609 /* backward_references_enc.h in Headers */, 4317394F1CDFC8B70008FEB9 /* demux.h in Headers */, 43CE757D1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, + 32D122202080B2EB003685A3 /* SDWebImageCache.h in Headers */, 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AC2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 80377C301F2F666300F89830 /* bit_writer_utils.h in Headers */, @@ -2737,6 +2778,7 @@ 3248476B201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 4A2CAE311AB4BB7500B6BC39 /* UIImage+WebP.h in Headers */, 323F8BF81F38EF770092B609 /* animi.h in Headers */, + 32D122322080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */, 80377C351F2F666300F89830 /* filters_utils.h in Headers */, 32F7C0862030719600873181 /* UIImage+Transform.h in Headers */, 80377C321F2F666300F89830 /* color_cache_utils.h in Headers */, @@ -2790,6 +2832,7 @@ 431738BD1CDFC2660008FEB9 /* decode.h in Headers */, 80377D0B1F2F66A100F89830 /* mips_macro.h in Headers */, 329A18591FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, + 32D122302080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */, 5376131A155AD0D5005750A4 /* SDWebImageDownloader.h in Headers */, 328BB6CD2082581100760D6C /* SDMemoryCache.h in Headers */, 4369C2771D9807EC007E863A /* UIView+WebCache.h in Headers */, @@ -2836,6 +2879,7 @@ 323F8B6E1F38EF770092B609 /* delta_palettization_enc.h in Headers */, 438096721CDFC08200DC626B /* MKAnnotationView+WebCache.h in Headers */, 43CE757C1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, + 32D1221E2080B2EB003685A3 /* SDWebImageCache.h in Headers */, 80377E8A1F2F66D000F89830 /* common_dec.h in Headers */, AB615303192DA24600A2D8E9 /* UIView+WebCacheOperation.h in Headers */, 323F8B501F38EF770092B609 /* backward_references_enc.h in Headers */, @@ -3151,6 +3195,7 @@ 80377DDE1F2F66A700F89830 /* rescaler_mips32.c in Sources */, 80377DCA1F2F66A700F89830 /* filters_sse2.c in Sources */, 80377EBE1F2F66D500F89830 /* quant_dec.c in Sources */, + 32D1222D2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */, 80377DB61F2F66A700F89830 /* dec_clip_tables.c in Sources */, 80377C5E1F2F666300F89830 /* utils.c in Sources */, 32B9B540206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, @@ -3193,6 +3238,7 @@ 80377DB51F2F66A700F89830 /* cpu.c in Sources */, 80377EC51F2F66D500F89830 /* webp_dec.c in Sources */, 80377DD61F2F66A700F89830 /* lossless_neon.c in Sources */, + 32D122272080B2EB003685A3 /* SDWebImageCache.m in Sources */, 00733A5C1BC4880000A5A117 /* UIButton+WebCache.m in Sources */, 80377EC01F2F66D500F89830 /* vp8_dec.c in Sources */, 80377C521F2F666300F89830 /* huffman_utils.c in Sources */, @@ -3276,6 +3322,7 @@ 4314D1341D0E0E3B004B36C9 /* UIImage+WebP.m in Sources */, 80377D3D1F2F66A700F89830 /* filters_mips_dsp_r2.c in Sources */, 323F8B751F38EF770092B609 /* filter_enc.c in Sources */, + 32D122252080B2EB003685A3 /* SDWebImageCache.m in Sources */, 80377D401F2F66A700F89830 /* filters_sse2.c in Sources */, 80377D1E1F2F66A700F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, 80377D291F2F66A700F89830 /* cost_sse2.c in Sources */, @@ -3318,6 +3365,7 @@ 80377D2F1F2F66A700F89830 /* dec_msa.c in Sources */, 323F8C151F38EF770092B609 /* muxinternal.c in Sources */, 80377D571F2F66A700F89830 /* rescaler_sse2.c in Sources */, + 32D1222B2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */, 43C892A11D9D6DDC0022038D /* demux.c in Sources */, 80377C131F2F666300F89830 /* bit_reader_utils.c in Sources */, 80377E9C1F2F66D400F89830 /* idec_dec.c in Sources */, @@ -3437,6 +3485,7 @@ 323F8BE21F38EF770092B609 /* vp8l_enc.c in Sources */, 431BB6A31D06D2C1006A3455 /* UIImageView+WebCache.m in Sources */, 80377E0C1F2F66A800F89830 /* filters_mips_dsp_r2.c in Sources */, + 32D122282080B2EB003685A3 /* SDWebImageCache.m in Sources */, 323F8B781F38EF770092B609 /* filter_enc.c in Sources */, 4369C2821D9807EC007E863A /* UIView+WebCache.m in Sources */, 80377E0F1F2F66A800F89830 /* filters_sse2.c in Sources */, @@ -3479,6 +3528,7 @@ 323F8BBE1F38EF770092B609 /* predictor_enc.c in Sources */, 80377E261F2F66A800F89830 /* rescaler_sse2.c in Sources */, 323F8C181F38EF770092B609 /* muxinternal.c in Sources */, + 32D1222E2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */, 80377C741F2F666400F89830 /* rescaler_utils.c in Sources */, 431BB6B11D06D2C1006A3455 /* UIView+WebCacheOperation.m in Sources */, 80377DF01F2F66A800F89830 /* alpha_processing_sse41.c in Sources */, @@ -3616,6 +3666,7 @@ 321E60C91F38E91700405457 /* UIImage+ForceDecode.m in Sources */, 80377E551F2F66A800F89830 /* filters.c in Sources */, 80377E731F2F66A800F89830 /* yuv_mips32.c in Sources */, + 32D1222F2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */, 4397D2911D0DDD8C00BB2784 /* MKAnnotationView+WebCache.m in Sources */, 4397D2921D0DDD8C00BB2784 /* SDWebImagePrefetcher.m in Sources */, 323F8BBF1F38EF770092B609 /* predictor_enc.c in Sources */, @@ -3628,6 +3679,7 @@ 80377E381F2F66A800F89830 /* argb_sse2.c in Sources */, 323F8B9B1F38EF770092B609 /* near_lossless_enc.c in Sources */, 32F21B5C20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, + 32D122292080B2EB003685A3 /* SDWebImageCache.m in Sources */, 80377E3B1F2F66A800F89830 /* cost_mips_dsp_r2.c in Sources */, 4397D29B1D0DDD8C00BB2784 /* SDWebImageDownloader.m in Sources */, 80377E711F2F66A800F89830 /* upsampling.c in Sources */, @@ -3801,6 +3853,7 @@ 80377C441F2F666300F89830 /* utils.c in Sources */, 80377D8D1F2F66A700F89830 /* lossless_enc_sse41.c in Sources */, 80377EAE1F2F66D400F89830 /* quant_dec.c in Sources */, + 32D1222C2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */, 80377D6E1F2F66A700F89830 /* cost_sse2.c in Sources */, 80377D991F2F66A700F89830 /* rescaler_mips32.c in Sources */, 32B9B53F206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, @@ -3843,6 +3896,7 @@ 80377D8C1F2F66A700F89830 /* lossless_enc_sse2.c in Sources */, 4A2CAE2C1AB4BB7500B6BC39 /* UIButton+WebCache.m in Sources */, 80377EB51F2F66D400F89830 /* webp_dec.c in Sources */, + 32D122262080B2EB003685A3 /* SDWebImageCache.m in Sources */, 80377D701F2F66A700F89830 /* cpu.c in Sources */, 80377D911F2F66A700F89830 /* lossless_neon.c in Sources */, 80377EB01F2F66D400F89830 /* vp8_dec.c in Sources */, @@ -3966,6 +4020,7 @@ 80377D031F2F66A100F89830 /* lossless_enc_sse41.c in Sources */, 80377E8E1F2F66D000F89830 /* quant_dec.c in Sources */, 80377CE41F2F66A100F89830 /* cost_sse2.c in Sources */, + 32D1222A2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */, 80377D0F1F2F66A100F89830 /* rescaler_mips32.c in Sources */, 323F8C081F38EF770092B609 /* muxedit.c in Sources */, 32B9B53D206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, @@ -4008,6 +4063,7 @@ A18A6CC9172DC28500419892 /* UIImage+GIF.m in Sources */, 80377E951F2F66D000F89830 /* webp_dec.c in Sources */, 80377CE61F2F66A100F89830 /* cpu.c in Sources */, + 32D122242080B2EB003685A3 /* SDWebImageCache.m in Sources */, 80377D071F2F66A100F89830 /* lossless_neon.c in Sources */, 80377E901F2F66D000F89830 /* vp8_dec.c in Sources */, 80377C041F2F665300F89830 /* huffman_utils.c in Sources */, diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 96860683..c22bff89 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -10,21 +10,7 @@ #import "SDWebImageCompat.h" #import "SDWebImageDefine.h" #import "SDImageCacheConfig.h" - -typedef NS_ENUM(NSInteger, SDImageCacheType) { - /** - * The image wasn't available the SDWebImage caches, but was downloaded from the web. - */ - SDImageCacheTypeNone, - /** - * The image was obtained from the disk cache. - */ - SDImageCacheTypeDisk, - /** - * The image was obtained from the memory cache. - */ - SDImageCacheTypeMemory -}; +#import "SDWebImageCache.h" typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { /** @@ -319,3 +305,10 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * - (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock; @end + +/** + * SDImageCache is the built-in image cache implementation for web image manager. It adopts `SDWebImageCache` protocol to provide the function for web image manager to use for image loading process. + */ +@interface SDImageCache (SDWebImageCache) + +@end diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 41756be1..b00746af 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -145,6 +145,15 @@ forKey:(nullable NSString *)key toDisk:(BOOL)toDisk completion:(nullable SDWebImageNoParamsBlock)completionBlock { + return [self storeImage:image imageData:imageData forKey:key toMemory:YES toDisk:toDisk completion:completionBlock]; +} + +- (void)storeImage:(nullable UIImage *)image + imageData:(nullable NSData *)imageData + forKey:(nullable NSString *)key + toMemory:(BOOL)toMemory + toDisk:(BOOL)toDisk + completion:(nullable SDWebImageNoParamsBlock)completionBlock { if (!image || !key) { if (completionBlock) { completionBlock(); @@ -152,7 +161,7 @@ return; } // if memory cache is enabled - if (self.config.shouldCacheImagesInMemory) { + if (toMemory && self.config.shouldCacheImagesInMemory) { NSUInteger cost = SDMemoryCacheCostForImage(image); [self.memCache setObject:image forKey:key cost:cost]; } @@ -426,11 +435,15 @@ } - (void)removeImageForKey:(nullable NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(nullable SDWebImageNoParamsBlock)completion { + [self removeImageForKey:key fromMemory:YES fromDisk:fromDisk withCompletion:completion]; +} + +- (void)removeImageForKey:(nullable NSString *)key fromMemory:(BOOL)fromMemory fromDisk:(BOOL)fromDisk withCompletion:(nullable SDWebImageNoParamsBlock)completion { if (key == nil) { return; } - if (self.config.shouldCacheImagesInMemory) { + if (fromMemory && self.config.shouldCacheImagesInMemory) { [self.memCache removeObjectForKey:key]; } @@ -544,3 +557,150 @@ @end +@implementation SDImageCache (SDWebImageCache) + +#pragma mark - SDWebImageCache + +- (id)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock { + SDImageCacheOptions cacheOptions = 0; + if (options & SDWebImageQueryDataWhenInMemory) cacheOptions |= SDImageCacheQueryDataWhenInMemory; + if (options & SDWebImageQueryDiskSync) cacheOptions |= SDImageCacheQueryDiskSync; + if (options & SDWebImageTransformAnimatedImage) cacheOptions |= SDImageCacheTransformAnimatedImage; + if (options & SDWebImageDecodeFirstFrameOnly) cacheOptions |= SDImageCacheDecodeFirstFrameOnly; + if (options & SDWebImagePreloadAllFrames) cacheOptions |= SDImageCachePreloadAllFrames; + return [self queryCacheOperationForKey:key options:cacheOptions context:context done:completionBlock]; +} + +- (void)storeImage:(UIImage *)image imageData:(NSData *)imageData forKey:(nullable NSString *)key cacheType:(SDImageCacheType)cacheType completion:(nullable SDWebImageNoParamsBlock)completionBlock { + switch (cacheType) { + case SDImageCacheTypeNone: { + [self storeImage:image imageData:imageData forKey:key toMemory:NO toDisk:NO completion:completionBlock]; + } + break; + case SDImageCacheTypeMemory: { + [self storeImage:image imageData:imageData forKey:key toMemory:YES toDisk:NO completion:completionBlock]; + } + break; + case SDImageCacheTypeDisk: { + [self storeImage:image imageData:imageData forKey:key toMemory:NO toDisk:YES completion:completionBlock]; + } + break; + case SDImageCacheTypeAll: { + [self storeImage:image imageData:imageData forKey:key toMemory:YES toDisk:YES completion:completionBlock]; + } + break; + default: { + if (completionBlock) { + completionBlock(); + } + } + break; + } +} + +- (void)removeImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(nullable SDWebImageNoParamsBlock)completionBlock { + switch (cacheType) { + case SDImageCacheTypeNone: { + [self removeImageForKey:key fromMemory:NO fromDisk:NO withCompletion:completionBlock]; + } + break; + case SDImageCacheTypeMemory: { + [self removeImageForKey:key fromMemory:YES fromDisk:NO withCompletion:completionBlock]; + } + break; + case SDImageCacheTypeDisk: { + [self removeImageForKey:key fromMemory:NO fromDisk:YES withCompletion:completionBlock]; + } + break; + case SDImageCacheTypeAll: { + [self removeImageForKey:key fromMemory:YES fromDisk:YES withCompletion:completionBlock]; + } + break; + default: { + if (completionBlock) { + completionBlock(); + } + } + break; + } +} + +- (void)containsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(nullable SDImageCacheContainsCompletionBlock)completionBlock { + switch (cacheType) { + case SDImageCacheTypeNone: { + if (completionBlock) { + completionBlock(SDImageCacheTypeNone); + } + } + break; + case SDImageCacheTypeMemory: { + BOOL isInMemoryCache = ([self imageFromMemoryCacheForKey:key] != nil); + if (completionBlock) { + completionBlock(isInMemoryCache ? SDImageCacheTypeMemory : SDImageCacheTypeNone); + } + } + break; + case SDImageCacheTypeDisk: { + [self diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) { + if (completionBlock) { + completionBlock(isInDiskCache ? SDImageCacheTypeDisk : SDImageCacheTypeNone); + } + }]; + } + break; + case SDImageCacheTypeAll: { + BOOL isInMemoryCache = ([self imageFromMemoryCacheForKey:key] != nil); + if (isInMemoryCache) { + if (completionBlock) { + completionBlock(SDImageCacheTypeMemory); + } + return; + } + [self diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) { + if (completionBlock) { + completionBlock(isInDiskCache ? SDImageCacheTypeDisk : SDImageCacheTypeNone); + } + }]; + } + break; + default: + if (completionBlock) { + completionBlock(SDImageCacheTypeNone); + } + break; + } +} + +- (void)clearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock { + switch (cacheType) { + case SDImageCacheTypeNone: { + return; + } + break; + case SDImageCacheTypeMemory: { + [self clearMemory]; + if (completionBlock) { + completionBlock(); + } + } + break; + case SDImageCacheTypeDisk: { + [self clearDiskOnCompletion:completionBlock]; + } + break; + case SDImageCacheTypeAll: { + [self clearMemory]; + [self clearDiskOnCompletion:completionBlock]; + } + break; + default: { + if (completionBlock) { + completionBlock(); + } + } + break; + } +} + +@end + diff --git a/SDWebImage/SDWebImageCache.h b/SDWebImage/SDWebImageCache.h new file mode 100644 index 00000000..ed101362 --- /dev/null +++ b/SDWebImage/SDWebImageCache.h @@ -0,0 +1,109 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" +#import "SDWebImageOperation.h" +#import "SDWebImageDefine.h" + +typedef NS_ENUM(NSInteger, SDImageCacheType) { + /** + * For query and contains op in response, means the image isn't available in the image cache + * For op in request, this type is not available and take no effect. + */ + SDImageCacheTypeNone, + /** + * For query and contains op in response, means the image was obtained from the disk cache. + * For op in request, means process only disk cache. + */ + SDImageCacheTypeDisk, + /** + * For query and contains op in response, means the image was obtained from the memory cache. + * For op in request, means process only memory cache. + */ + SDImageCacheTypeMemory, + /** + * For query and contains op in response, this type is not available and take no effect. + * For op in request, means process both memory cache and disk cache. + */ + SDImageCacheTypeAll +}; + +typedef void(^SDImageCacheQueryCompletionBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType); +typedef void(^SDImageCacheContainsCompletionBlock)(SDImageCacheType containsCacheType); + +/** + This is the image cache protocol to provide custom image cache for `SDWebImageManager`. + Though the best practice to custom image cache, is to write your own class which conform `SDMemoryCache` or `SDDiskCache` protocol for `SDImageCache` class (See more on `SDImageCacheConfig.memoryCacheClass & SDImageCacheConfig.diskCacheClass`). + However, if your own cache implementation contains more advanced feature beyond `SDImageCache` itself, you can consider to provide this instead. For example, you can even use a cache manager like `SDWebImageCachesManager` to register multiple caches. + */ +@protocol SDWebImageCache + +@required +/** + Query the cached image from image cache for given key. The operation can be used to cancel the query. + If image is cached in memory, completion is called synchronously, else aynchronously and depends on the options arg (See `SDWebImageQueryDiskSync`) + + @param key The image cache key + @param options A mask to specify options to use for this query + @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + @param completionBlock The completion block. Will not get called if the operation is cancelled + @return The operation for this query + */ +- (nullable id)queryImageForKey:(nullable NSString *)key + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock; + +/** + Store the image into image cache for the given key. If cache type is memory only, completion is called synchronously, else aynchronously. + + @param image The image to store + @param imageData The image data to be used for disk storage + @param key The image cache key + @param cacheType The image store op cache type + @param completionBlock A block executed after the operation is finished + */ +- (void)storeImage:(nullable UIImage *)image + imageData:(nullable NSData *)imageData + forKey:(nullable NSString *)key + cacheType:(SDImageCacheType)cacheType + completion:(nullable SDWebImageNoParamsBlock)completionBlock; + +/** + Remove the image from image cache for the given key. If cache type is memory only, completion is called synchronously, else aynchronously. + + @param key The image cache key + @param cacheType The image remove op cache type + @param completionBlock A block executed after the operation is finished + */ +- (void)removeImageForKey:(nullable NSString *)key + cacheType:(SDImageCacheType)cacheType + completion:(nullable SDWebImageNoParamsBlock)completionBlock; + +/** + Check if image cache contains the image for the given key (does not load the image). If image is cached in memory, completion is called synchronously, else aynchronously. + + @param key The image cache key + @param cacheType The image contains op cache type + @param completionBlock A block executed after the operation is finished. + */ +- (void)containsImageForKey:(nullable NSString *)key + cacheType:(SDImageCacheType)cacheType + completion:(nullable SDImageCacheContainsCompletionBlock)completionBlock; + +/** + Clear all the cached images for image cache. If cache type is memory only, completion is called synchronously, else aynchronously. + + @param cacheType The image clear op cache type + @param completionBlock A block executed after the operation is finished + */ +- (void)clearWithCacheType:(SDImageCacheType)cacheType + completion:(nullable SDWebImageNoParamsBlock)completionBlock; + +@end diff --git a/SDWebImage/SDWebImageCache.m b/SDWebImage/SDWebImageCache.m new file mode 100644 index 00000000..8203e7bd --- /dev/null +++ b/SDWebImage/SDWebImageCache.m @@ -0,0 +1,9 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCache.h" diff --git a/SDWebImage/SDWebImageCachesManager.h b/SDWebImage/SDWebImageCachesManager.h new file mode 100644 index 00000000..c7f508dc --- /dev/null +++ b/SDWebImage/SDWebImageCachesManager.h @@ -0,0 +1,77 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCache.h" + +typedef NS_ENUM(NSUInteger, SDWebImageCachesManagerOperationPolicy) { + SDWebImageCachesManagerOperationPolicySerial, // process all caches serially (from the highest priority to the lowest priority cache by order) + SDWebImageCachesManagerOperationPolicyConcurrent, // process all caches concurrently + SDWebImageCachesManagerOperationPolicyHighestOnly, // process the highest priority cache only + SDWebImageCachesManagerOperationPolicyLowestOnly // process the lowest priority cache only +}; + +@interface SDWebImageCachesManager : NSObject + +/** + Returns the global shared caches manager instance. + */ +@property (nonatomic, class, readonly, nonnull) SDWebImageCachesManager *sharedManager; + +// These are op policy for cache manager. + +/** + Operation policy for query op. + Defaults to `Serial`, means query all caches serially (one completion called then next begin) until one cache query success (`image` != nil). + */ +@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy queryOperationPolicy; + +/** + Operation policy for store op. + Defaults to `HighestOnly`, means store to the highest priority cache only. + */ +@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy storeOperationPolicy; + +/** + Operation policy for remove op. + Defaults to `Concurrent`, means remove all caches concurrently. + */ +@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy removeOperationPolicy; + +/** + Operation policy for contains op. + Defaults to `Serial`, means check all caches serially (one completion called then next begin) until one cache check success (`containsCacheType` != None). + */ +@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy containsOperationPolicy; + +/** + Operation policy for clear op. + Defaults to `Concurrent`, means clear all caches concurrently. + */ +@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy clearOperationPolicy; + +/** + All caches in caches manager. The caches array is a priority queue, which means the later added cache will have the highest priority + */ +@property (atomic, copy, readwrite, nullable) NSArray> *caches; + +/** + Add a new cache to the end of caches array. Which has the highest priority. + + @param cache cache + */ +- (void)addCache:(nonnull id)cache; + +/** + Remove a cache in the caches array. + + @param cache cache + */ +- (void)removeCache:(nonnull id)cache; + +@end diff --git a/SDWebImage/SDWebImageCachesManager.m b/SDWebImage/SDWebImageCachesManager.m new file mode 100644 index 00000000..e7644774 --- /dev/null +++ b/SDWebImage/SDWebImageCachesManager.m @@ -0,0 +1,582 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCachesManager.h" + +// This is used for operation management, but not for operation queue execute +@interface SDWebImageCachesManagerOperation : NSOperation + +@property (nonatomic, assign, readonly) NSUInteger pendingCount; + +- (void)beginWithTotalCount:(NSUInteger)totalCount; +- (void)completeOne; +- (void)done; + +@end + +@implementation SDWebImageCachesManagerOperation + +@synthesize executing = _executing; +@synthesize finished = _finished; +@synthesize cancelled = _cancelled; + +- (void)beginWithTotalCount:(NSUInteger)totalCount { + self.executing = YES; + self.finished = NO; + _pendingCount = totalCount; +} + +- (void)completeOne { + _pendingCount = _pendingCount > 0 ? _pendingCount - 1 : 0; +} + +- (void)cancel { + self.cancelled = YES; + [self reset]; +} + +- (void)done { + self.finished = YES; + self.executing = NO; + [self reset]; +} + +- (void)reset { + _pendingCount = 0; +} + +- (void)setFinished:(BOOL)finished { + [self willChangeValueForKey:@"isFinished"]; + _finished = finished; + [self didChangeValueForKey:@"isFinished"]; +} + +- (void)setExecuting:(BOOL)executing { + [self willChangeValueForKey:@"isExecuting"]; + _executing = executing; + [self didChangeValueForKey:@"isExecuting"]; +} + +- (void)setCancelled:(BOOL)cancelled { + [self willChangeValueForKey:@"isCancelled"]; + _cancelled = cancelled; + [self didChangeValueForKey:@"isCancelled"]; +} + +@end + +@implementation SDWebImageCachesManager + ++ (SDWebImageCachesManager *)sharedManager { + static dispatch_once_t onceToken; + static SDWebImageCachesManager *manager; + dispatch_once(&onceToken, ^{ + manager = [[SDWebImageCachesManager alloc] init]; + }); + return manager; +} + +- (instancetype)init { + self = [super init]; + if (self) { + self.queryOperationPolicy = SDWebImageCachesManagerOperationPolicySerial; + self.storeOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly; + self.removeOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent; + self.containsOperationPolicy = SDWebImageCachesManagerOperationPolicySerial; + self.clearOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent; + } + return self; +} + +#pragma mark - Cache IO operations + +- (void)addCache:(id)cache { + if (![cache conformsToProtocol:@protocol(SDWebImageCache)]) { + return; + } + NSMutableArray> *mutableCaches = [self.caches mutableCopy]; + if (!mutableCaches) { + mutableCaches = [NSMutableArray array]; + } + [mutableCaches addObject:cache]; + self.caches = [mutableCaches copy]; +} + +- (void)removeCache:(id)cache { + if (![cache conformsToProtocol:@protocol(SDWebImageCache)]) { + return; + } + NSMutableArray> *mutableCaches = [self.caches mutableCopy]; + [mutableCaches removeObject:cache]; + self.caches = [mutableCaches copy]; +} + +#pragma mark - SDWebImageCache + +- (id)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock { + if (!key) { + return nil; + } + NSArray> *caches = [self.caches copy]; + NSUInteger count = caches.count; + if (count == 0) { + return nil; + } else if (count == 1) { + return [caches.firstObject queryImageForKey:key options:options context:context completion:completionBlock]; + } + switch (self.queryOperationPolicy) { + case SDWebImageCachesManagerOperationPolicyHighestOnly: { + id cache = caches.lastObject; + return [cache queryImageForKey:key options:options context:context completion:completionBlock]; + } + break; + case SDWebImageCachesManagerOperationPolicyLowestOnly: { + id cache = caches.firstObject; + return [cache queryImageForKey:key options:options context:context completion:completionBlock]; + } + break; + case SDWebImageCachesManagerOperationPolicyConcurrent: { + SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new]; + [operation beginWithTotalCount:caches.count]; + [self concurrentQueryImageForKey:key options:options context:context completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; + return operation; + } + break; + case SDWebImageCachesManagerOperationPolicySerial: { + SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new]; + [operation beginWithTotalCount:caches.count]; + [self serialQueryImageForKey:key options:options context:context completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; + return operation; + } + break; + default: + return nil; + break; + } +} + +- (void)storeImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock { + if (!key) { + return; + } + NSArray> *caches = [self.caches copy]; + NSUInteger count = caches.count; + if (count == 0) { + return; + } else if (count == 1) { + [caches.firstObject storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock]; + return; + } + switch (self.storeOperationPolicy) { + case SDWebImageCachesManagerOperationPolicyHighestOnly: { + id cache = caches.lastObject; + [cache storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock]; + } + break; + case SDWebImageCachesManagerOperationPolicyLowestOnly: { + id cache = caches.firstObject; + [cache storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock]; + } + break; + case SDWebImageCachesManagerOperationPolicyConcurrent: { + SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new]; + [operation beginWithTotalCount:caches.count]; + [self concurrentStoreImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; + } + break; + case SDWebImageCachesManagerOperationPolicySerial: { + [self serialStoreImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator]; + } + break; + default: + break; + } +} + +- (void)removeImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock { + if (!key) { + return; + } + NSArray> *caches = [self.caches copy]; + NSUInteger count = caches.count; + if (count == 0) { + return; + } else if (count == 1) { + [caches.firstObject removeImageForKey:key cacheType:cacheType completion:completionBlock]; + return; + } + switch (self.removeOperationPolicy) { + case SDWebImageCachesManagerOperationPolicyHighestOnly: { + id cache = caches.lastObject; + [cache removeImageForKey:key cacheType:cacheType completion:completionBlock]; + } + break; + case SDWebImageCachesManagerOperationPolicyLowestOnly: { + id cache = caches.firstObject; + [cache removeImageForKey:key cacheType:cacheType completion:completionBlock]; + } + break; + case SDWebImageCachesManagerOperationPolicyConcurrent: { + SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new]; + [operation beginWithTotalCount:caches.count]; + [self concurrentRemoveImageForKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; + } + break; + case SDWebImageCachesManagerOperationPolicySerial: { + [self serialRemoveImageForKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator]; + } + break; + default: + break; + } +} + +- (void)containsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheContainsCompletionBlock)completionBlock { + if (!key) { + return; + } + NSArray> *caches = [self.caches copy]; + NSUInteger count = caches.count; + if (count == 0) { + return; + } else if (count == 1) { + [caches.firstObject containsImageForKey:key cacheType:cacheType completion:completionBlock]; + return; + } + switch (self.clearOperationPolicy) { + case SDWebImageCachesManagerOperationPolicyHighestOnly: { + id cache = caches.lastObject; + [cache containsImageForKey:key cacheType:cacheType completion:completionBlock]; + } + break; + case SDWebImageCachesManagerOperationPolicyLowestOnly: { + id cache = caches.firstObject; + [cache containsImageForKey:key cacheType:cacheType completion:completionBlock]; + } + break; + case SDWebImageCachesManagerOperationPolicyConcurrent: { + SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new]; + [operation beginWithTotalCount:caches.count]; + [self concurrentContainsImageForKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; + } + break; + case SDWebImageCachesManagerOperationPolicySerial: { + SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new]; + [operation beginWithTotalCount:caches.count]; + [self serialContainsImageForKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; + } + break; + default: + break; + } +} + +- (void)clearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock { + NSArray> *caches = [self.caches copy]; + NSUInteger count = caches.count; + if (count == 0) { + return; + } else if (count == 1) { + [caches.firstObject clearWithCacheType:cacheType completion:completionBlock]; + return; + } + switch (self.clearOperationPolicy) { + case SDWebImageCachesManagerOperationPolicyHighestOnly: { + id cache = caches.lastObject; + [cache clearWithCacheType:cacheType completion:completionBlock]; + } + break; + case SDWebImageCachesManagerOperationPolicyLowestOnly: { + id cache = caches.firstObject; + [cache clearWithCacheType:cacheType completion:completionBlock]; + } + break; + case SDWebImageCachesManagerOperationPolicyConcurrent: { + SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new]; + [operation beginWithTotalCount:caches.count]; + [self concurrentClearWithCacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; + } + break; + case SDWebImageCachesManagerOperationPolicySerial: { + [self serialClearWithCacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator]; + } + break; + default: + break; + } +} + +#pragma mark - Concurrent Operation + +- (void)concurrentQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation { + NSParameterAssert(enumerator); + NSParameterAssert(operation); + for (id cache in enumerator) { + [cache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { + if (operation.isCancelled) { + // Cancelled + return; + } + if (operation.isFinished) { + // Finished + return; + } + [operation completeOne]; + if (image) { + // Success + [operation done]; + if (completionBlock) { + completionBlock(image, data, cacheType); + } + return; + } + if (operation.pendingCount == 0) { + // Complete + [operation done]; + if (completionBlock) { + completionBlock(nil, nil, SDImageCacheTypeNone); + } + } + }]; + } +} + +- (void)concurrentStoreImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation { + NSParameterAssert(enumerator); + NSParameterAssert(operation); + for (id cache in enumerator) { + [cache storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:^{ + if (operation.isCancelled) { + // Cancelled + return; + } + if (operation.isFinished) { + // Finished + return; + } + [operation completeOne]; + if (operation.pendingCount == 0) { + // Complete + [operation done]; + if (completionBlock) { + completionBlock(); + } + } + }]; + } +} + +- (void)concurrentRemoveImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation { + NSParameterAssert(enumerator); + NSParameterAssert(operation); + for (id cache in enumerator) { + [cache removeImageForKey:key cacheType:cacheType completion:^{ + if (operation.isCancelled) { + // Cancelled + return; + } + if (operation.isFinished) { + // Finished + return; + } + [operation completeOne]; + if (operation.pendingCount == 0) { + // Complete + [operation done]; + if (completionBlock) { + completionBlock(); + } + } + }]; + } +} + +- (void)concurrentContainsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheContainsCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation { + NSParameterAssert(enumerator); + NSParameterAssert(operation); + for (id cache in enumerator) { + [cache containsImageForKey:key cacheType:cacheType completion:^(SDImageCacheType containsCacheType) { + if (operation.isCancelled) { + // Cancelled + return; + } + if (operation.isFinished) { + // Finished + return; + } + [operation completeOne]; + if (containsCacheType != SDImageCacheTypeNone) { + // Success + [operation done]; + if (completionBlock) { + completionBlock(containsCacheType); + } + return; + } + if (operation.pendingCount == 0) { + // Complete + [operation done]; + if (completionBlock) { + completionBlock(SDImageCacheTypeNone); + } + } + }]; + } +} + +- (void)concurrentClearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation { + NSParameterAssert(enumerator); + NSParameterAssert(operation); + for (id cache in enumerator) { + [cache clearWithCacheType:cacheType completion:^{ + if (operation.isCancelled) { + // Cancelled + return; + } + if (operation.isFinished) { + // Finished + return; + } + [operation completeOne]; + if (operation.pendingCount == 0) { + // Complete + [operation done]; + if (completionBlock) { + completionBlock(); + } + } + }]; + } +} + +#pragma mark - Serial Operation + +- (void)serialQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation { + NSParameterAssert(enumerator); + NSParameterAssert(operation); + id cache = enumerator.nextObject; + if (!cache) { + // Complete + [operation done]; + if (completionBlock) { + completionBlock(nil, nil, SDImageCacheTypeNone); + } + return; + } + __weak typeof(self) wself = self; + [cache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { + if (operation.isCancelled) { + // Cancelled + return; + } + if (operation.isFinished) { + // Finished + return; + } + [operation completeOne]; + if (image) { + // Success + [operation done]; + if (completionBlock) { + completionBlock(image, data, cacheType); + } + return; + } + // Next + [wself serialQueryImageForKey:key options:options context:context completion:completionBlock enumerator:enumerator operation:operation]; + }]; +} + +- (void)serialStoreImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator { + NSParameterAssert(enumerator); + id cache = enumerator.nextObject; + if (!cache) { + // Complete + if (completionBlock) { + completionBlock(); + } + return; + } + __weak typeof(self) wself = self; + [cache storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:^{ + // Next + [wself serialStoreImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock enumerator:enumerator]; + }]; +} + +- (void)serialRemoveImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator { + NSParameterAssert(enumerator); + id cache = enumerator.nextObject; + if (!cache) { + // Complete + if (completionBlock) { + completionBlock(); + } + return; + } + __weak typeof(self) wself = self; + [cache removeImageForKey:key cacheType:cacheType completion:^{ + // Next + [wself serialRemoveImageForKey:key cacheType:cacheType completion:completionBlock enumerator:enumerator]; + }]; +} + +- (void)serialContainsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheContainsCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation { + NSParameterAssert(enumerator); + NSParameterAssert(operation); + id cache = enumerator.nextObject; + if (!cache) { + // Complete + [operation done]; + if (completionBlock) { + completionBlock(SDImageCacheTypeNone); + } + return; + } + __weak typeof(self) wself = self; + [cache containsImageForKey:key cacheType:cacheType completion:^(SDImageCacheType containsCacheType) { + if (operation.isCancelled) { + // Cancelled + return; + } + if (operation.isFinished) { + // Finished + return; + } + [operation completeOne]; + if (containsCacheType != SDImageCacheTypeNone) { + // Success + [operation done]; + if (completionBlock) { + completionBlock(containsCacheType); + } + return; + } + // Next + [wself serialContainsImageForKey:key cacheType:cacheType completion:completionBlock enumerator:enumerator operation:operation]; + }]; +} + +- (void)serialClearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator { + NSParameterAssert(enumerator); + id cache = enumerator.nextObject; + if (!cache) { + // Complete + if (completionBlock) { + completionBlock(); + } + return; + } + __weak typeof(self) wself = self; + [cache clearWithCacheType:cacheType completion:^{ + // Next + [wself serialClearWithCacheType:cacheType completion:completionBlock enumerator:enumerator]; + }]; +} + +@end diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index b1724058..6f338d95 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -8,8 +8,8 @@ #import "SDWebImageCompat.h" #import "SDWebImageOperation.h" +#import "SDWebImageCache.h" #import "SDWebImageDownloader.h" -#import "SDImageCache.h" #import "SDWebImageTransformer.h" #import "SDWebImageCacheKeyFilter.h" #import "SDWebImageCacheSerializer.h" @@ -99,7 +99,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; /** * The image cache used by manager to query image cache. */ -@property (strong, nonatomic, readonly, nonnull) SDImageCache *imageCache; +@property (strong, nonatomic, readonly, nonnull) id imageCache; /** * The image downloader used by manager to download image. @@ -154,6 +154,18 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; */ @property (nonatomic, assign, readonly, getter=isRunning) BOOL running; +/** + The default image cache when the manager which is created with no arguments. Such as shared manager or init. + Defaults to nil. Means using `SDImageCache.sharedImageCache` + */ +@property (nonatomic, class, nullable) id defaultImageCache; + +/** + The default image downloader for manager which is created with no arguments. Such as shared manager or init. + Defaults to nil. Means using `SDWebImageDownloader.sharedDownloader` + */ +@property (nonatomic, class, nullable) SDWebImageDownloader *defaultImageDownloader; + /** * Returns global shared manager instance. */ @@ -163,7 +175,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; * Allows to specify instance of cache and image downloader used with image manager. * @return new instance of `SDWebImageManager` with specified cache and downloader. */ -- (nonnull instancetype)initWithCache:(nonnull SDImageCache *)cache downloader:(nonnull SDWebImageDownloader *)downloader NS_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithCache:(nonnull id)cache downloader:(nonnull SDWebImageDownloader *)downloader NS_DESIGNATED_INITIALIZER; /** * Downloads the image at the given URL if not present in cache or return the cached version otherwise. @@ -213,46 +225,13 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nonnull SDInternalCompletionBlock)completedBlock; -/** - * Saves image to cache for given URL - * - * @param image The image to cache - * @param url The URL to the image - * - */ - -- (void)saveImageToCache:(nullable UIImage *)image forURL:(nullable NSURL *)url; - /** * Cancel all current operations */ - (void)cancelAll; /** - * Async check if image has already been cached - * - * @param url image url - * @param completionBlock the block to be executed when the check is finished - * - * @note the completion block is always executed on the main queue - */ -- (void)cachedImageExistsForURL:(nullable NSURL *)url - completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock; - -/** - * Async check if image has already been cached on disk only - * - * @param url image url - * @param completionBlock the block to be executed when the check is finished - * - * @note the completion block is always executed on the main queue - */ -- (void)diskImageExistsForURL:(nullable NSURL *)url - completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock; - - -/** - *Return the cache key for a given URL + * Return the cache key for a given URL */ - (nullable NSString *)cacheKeyForURL:(nullable NSURL *)url; diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 583e3202..e163d617 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -7,10 +7,14 @@ */ #import "SDWebImageManager.h" +#import "SDImageCache.h" #import "NSImage+Additions.h" #import "UIImage+WebCache.h" #import "SDAnimatedImage.h" +static id _defaultImageCache; +static SDWebImageDownloader *_defaultImageDownloader; + @interface SDWebImageCombinedOperation () @property (assign, nonatomic, getter = isCancelled) BOOL cancelled; @@ -31,6 +35,28 @@ @implementation SDWebImageManager ++ (id)defaultImageCache { + return _defaultImageCache; +} + ++ (void)setDefaultImageCache:(id)defaultImageCache { + if (defaultImageCache && ![defaultImageCache conformsToProtocol:@protocol(SDWebImageCache)]) { + return; + } + _defaultImageCache = defaultImageCache; +} + ++ (SDWebImageDownloader *)defaultImageDownloader { + return _defaultImageDownloader; +} + ++ (void)setDefaultImageDownloader:(SDWebImageDownloader *)defaultImageDownloader { + if (defaultImageDownloader && ![defaultImageDownloader isKindOfClass:[SDWebImageDownloader class]]) { + return; + } + _defaultImageDownloader = defaultImageDownloader; +} + + (nonnull instancetype)sharedManager { static dispatch_once_t once; static id instance; @@ -41,12 +67,18 @@ } - (nonnull instancetype)init { - SDImageCache *cache = [SDImageCache sharedImageCache]; - SDWebImageDownloader *downloader = [SDWebImageDownloader sharedDownloader]; + id cache = [[self class] defaultImageCache]; + if (!cache) { + cache = [SDImageCache sharedImageCache]; + } + SDWebImageDownloader *downloader = [[self class] defaultImageDownloader]; + if (!downloader) { + downloader = [SDWebImageDownloader sharedDownloader]; + } return [self initWithCache:cache downloader:downloader]; } -- (nonnull instancetype)initWithCache:(nonnull SDImageCache *)cache downloader:(nonnull SDWebImageDownloader *)downloader { +- (nonnull instancetype)initWithCache:(nonnull id)cache downloader:(nonnull SDWebImageDownloader *)downloader { if ((self = [super init])) { _imageCache = cache; _imageDownloader = downloader; @@ -76,42 +108,6 @@ return SDScaledImageForKey(key, image); } -- (void)cachedImageExistsForURL:(nullable NSURL *)url - completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock { - NSString *key = [self cacheKeyForURL:url]; - - BOOL isInMemoryCache = ([self.imageCache imageFromMemoryCacheForKey:key] != nil); - - if (isInMemoryCache) { - // making sure we call the completion block on the main queue - dispatch_async(dispatch_get_main_queue(), ^{ - if (completionBlock) { - completionBlock(YES); - } - }); - return; - } - - [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) { - // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch - if (completionBlock) { - completionBlock(isInDiskCache); - } - }]; -} - -- (void)diskImageExistsForURL:(nullable NSURL *)url - completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock { - NSString *key = [self cacheKeyForURL:url]; - - [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) { - // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch - if (completionBlock) { - completionBlock(isInDiskCache); - } - }]; -} - - (SDWebImageCombinedOperation *)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDInternalCompletionBlock)completedBlock { return [self loadImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock]; } @@ -154,14 +150,6 @@ [self.runningOperations addObject:operation]; } - SDImageCacheOptions cacheOptions = 0; - if (options & SDWebImageQueryDataWhenInMemory) cacheOptions |= SDImageCacheQueryDataWhenInMemory; - if (options & SDWebImageQueryDiskSync) cacheOptions |= SDImageCacheQueryDiskSync; - if (options & SDWebImageScaleDownLargeImages) cacheOptions |= SDImageCacheScaleDownLargeImages; - if (options & SDWebImageTransformAnimatedImage) cacheOptions |= SDImageCacheTransformAnimatedImage; - if (options & SDWebImageDecodeFirstFrameOnly) cacheOptions |= SDImageCacheDecodeFirstFrameOnly; - if (options & SDWebImagePreloadAllFrames) cacheOptions |= SDImageCachePreloadAllFrames; - // Image transformer id transformer; if ([context valueForKey:SDWebImageContextCustomTransformer]) { @@ -195,7 +183,7 @@ } __weak SDWebImageCombinedOperation *weakOperation = operation; - operation.cacheOperation = [self.imageCache queryCacheOperationForKey:key options:cacheOptions context:context done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) { + operation.cacheOperation = [self.imageCache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable cachedImage, NSData * _Nullable cachedData, SDImageCacheType cacheType) { __strong __typeof(weakOperation) strongOperation = weakOperation; if (!strongOperation || strongOperation.isCancelled) { [self safelyRemoveOperationFromRunning:strongOperation]; @@ -271,7 +259,10 @@ } } - BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly); + SDImageCacheType storeCacheType = SDImageCacheTypeAll; + if (options & SDWebImageCacheMemoryOnly) { + storeCacheType = SDImageCacheTypeMemory; + } // We've done the scale process in SDWebImageDownloader with the shared manager, this is used for custom manager and avoid extra scale. if (self != [SDWebImageManager sharedManager] && cacheKeyFilter && downloadedImage && ![downloadedImage conformsToProtocol:@protocol(SDAnimatedImage)]) { @@ -294,7 +285,7 @@ } else { cacheData = (imageWasTransformed ? nil : downloadedData); } - [self.imageCache storeImage:transformedImage imageData:cacheData forKey:cacheKey toDisk:cacheOnDisk completion:nil]; + [self.imageCache storeImage:transformedImage imageData:cacheData forKey:cacheKey cacheType:storeCacheType completion:nil]; } [self callCompletionBlockForOperation:strongSubOperation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; @@ -304,10 +295,10 @@ if (cacheSerializer) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ NSData *cacheData = [cacheSerializer cacheDataWithImage:downloadedImage originalData:downloadedData imageURL:url]; - [self.imageCache storeImage:downloadedImage imageData:cacheData forKey:key toDisk:cacheOnDisk completion:nil]; + [self.imageCache storeImage:downloadedImage imageData:cacheData forKey:key cacheType:storeCacheType completion:nil]; }); } else { - [self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key toDisk:cacheOnDisk completion:nil]; + [self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key cacheType:storeCacheType completion:nil]; } } [self callCompletionBlockForOperation:strongSubOperation completion:completedBlock image:downloadedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; @@ -331,13 +322,6 @@ return operation; } -- (void)saveImageToCache:(nullable UIImage *)image forURL:(nullable NSURL *)url { - if (image && url) { - NSString *key = [self cacheKeyForURL:url]; - [self.imageCache storeImage:image forKey:key toDisk:YES completion:nil]; - } -} - - (void)cancelAll { @synchronized (self.runningOperations) { NSArray *copiedOperations = [self.runningOperations copy]; diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index 2f57ac06..72205397 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -28,6 +28,8 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import +#import +#import #import #import #import From 1220f735079d1fd6770c1c947519d3847f19cae9 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 13 Apr 2018 19:35:55 +0800 Subject: [PATCH 140/361] Expose the sync version of remove API --- SDWebImage/SDImageCache.h | 27 ++++++++++++++++++++++++++- SDWebImage/SDImageCache.m | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index c22bff89..09a04710 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -167,6 +167,15 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * toDisk:(BOOL)toDisk completion:(nullable SDWebImageNoParamsBlock)completionBlock; +/** + * Synchronously store image into memory cache at the given key. + * + * @param image The image to store + * @param key The unique image cache key, usually it's image absolute URL + */ +- (void)storeImageToMemory:(nullable UIImage*)image + forKey:(nullable NSString *)key; + /** * Synchronously store image NSData into disk cache at the given key. * @@ -177,7 +186,7 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * forKey:(nullable NSString *)key; -#pragma mark - Query and Retrieve Ops +#pragma mark - Contains and Check Ops /** * Asynchronously check if image exists in disk cache already (does not load the image) @@ -195,6 +204,8 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * */ - (BOOL)diskImageDataExistsWithKey:(nullable NSString *)key; +#pragma mark - Query and Retrieve Ops + /** * Asynchronously queries the cache with operation and call the completion when done. * @@ -268,6 +279,20 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * */ - (void)removeImageForKey:(nullable NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(nullable SDWebImageNoParamsBlock)completion; +/** + Synchronously remove the image from memory cache. + + @param key The unique image cache key + */ +- (void)removeImageFromMemoryForKey:(nullable NSString *)key; + +/** + Synchronously remove the image from disk cache. + + @param key The unique image cache key + */ +- (void)removeImageFromDiskForKey:(nullable NSString *)key; + #pragma mark - Cache clean Ops /** diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index b00746af..17d3ad8a 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -196,6 +196,14 @@ } } +- (void)storeImageToMemory:(UIImage *)image forKey:(NSString *)key { + if (!image || !key) { + return; + } + NSUInteger cost = SDMemoryCacheCostForImage(image); + [self.memCache setObject:image forKey:key cost:cost]; +} + - (void)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key { if (!imageData || !key) { @@ -462,6 +470,32 @@ } } +- (void)removeImageFromMemoryForKey:(NSString *)key { + if (!key) { + return; + } + + [self.memCache removeObjectForKey:key]; +} + +- (void)removeImageFromDiskForKey:(NSString *)key { + if (!key) { + return; + } + dispatch_sync(self.ioQueue, ^{ + [self _removeImageFromDiskForKey:key]; + }); +} + +// Make sure to call form io queue by caller +- (void)_removeImageFromDiskForKey:(NSString *)key { + if (!key) { + return; + } + + [self.diskCache removeDataForKey:key]; +} + #pragma mark - Cache clean Ops - (void)clearMemory { From 2c7d1a465ac8c9f4088cad892753dae59f32dc4a Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 13 Apr 2018 19:38:37 +0800 Subject: [PATCH 141/361] Update the tests for web cache protocol and caches manager --- Tests/Tests/SDAnimatedImageTest.m | 1 + Tests/Tests/SDImageCacheTests.m | 328 +++++++++++++++++++----- Tests/Tests/SDWebImageManagerTests.m | 27 +- Tests/Tests/SDWebImagePrefetcherTests.m | 1 + 4 files changed, 273 insertions(+), 84 deletions(-) diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index 0434b948..88da836c 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -8,6 +8,7 @@ */ #import "SDTestCase.h" +#import #import #import #import diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index 35191bd1..e8050382 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -9,11 +9,13 @@ #import "SDTestCase.h" #import #import +#import #import "SDWebImageTestDecoder.h" #import "SDMockFileManager.h" #import "SDWebImageTestCache.h" -NSString *kImageTestKey = @"TestImageKey.jpg"; +static NSString *kTestImageKeyJPEG = @"TestImageKey.jpg"; +static NSString *kTestImageKeyPNG = @"TestImageKey.png"; @interface SDImageCache () @@ -27,6 +29,14 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; @implementation SDImageCacheTests ++ (void)setUp { + [[SDWebImageCachesManager sharedManager] addCache:[SDImageCache sharedImageCache]]; +} + ++ (void)tearDown { + [[SDWebImageCachesManager sharedManager] removeCache:[SDImageCache sharedImageCache]]; +} + - (void)test01SharedImageCache { expect([SDImageCache sharedImageCache]).toNot.beNil(); } @@ -43,14 +53,14 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test04ClearDiskCache{ XCTestExpectation *expectation = [self expectationWithDescription:@"Clear disk cache"]; - [[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil]; + [[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:nil]; [[SDImageCache sharedImageCache] clearDiskOnCompletion:^{ - expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.equal([self imageForTesting]); - [[SDImageCache sharedImageCache] diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) { + expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal([self testJPEGImage]); + [[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) { if (!isInCache) { [[SDImageCache sharedImageCache] calculateSizeWithCompletionBlock:^(NSUInteger fileCount, NSUInteger totalSize) { expect(fileCount).to.equal(0); - [[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{ + [[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{ [expectation fulfill]; }]; }]; @@ -65,12 +75,12 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test05ClearMemoryCache{ XCTestExpectation *expectation = [self expectationWithDescription:@"Clear memory cache"]; - [[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:^{ + [[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:^{ [[SDImageCache sharedImageCache] clearMemory]; - expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.beNil; - [[SDImageCache sharedImageCache] diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) { + expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil; + [[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) { if (isInCache) { - [[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{ + [[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{ [expectation fulfill]; }]; } else { @@ -85,12 +95,12 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test06InsertionOfImage { XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey"]; - UIImage *image = [self imageForTesting]; - [[SDImageCache sharedImageCache] storeImage:image forKey:kImageTestKey completion:nil]; - expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.equal(image); - [[SDImageCache sharedImageCache] diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) { + UIImage *image = [self testJPEGImage]; + [[SDImageCache sharedImageCache] storeImage:image forKey:kTestImageKeyJPEG completion:nil]; + expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal(image); + [[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) { if (isInCache) { - [[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{ + [[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{ [expectation fulfill]; }]; } else { @@ -104,12 +114,12 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test07InsertionOfImageForcingDiskStorage { XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey toDisk=YES"]; - UIImage *image = [self imageForTesting]; - [[SDImageCache sharedImageCache] storeImage:image forKey:kImageTestKey toDisk:YES completion:nil]; - expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.equal(image); - [[SDImageCache sharedImageCache] diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) { + UIImage *image = [self testJPEGImage]; + [[SDImageCache sharedImageCache] storeImage:image forKey:kTestImageKeyJPEG toDisk:YES completion:nil]; + expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal(image); + [[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) { if (isInCache) { - [[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{ + [[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{ [expectation fulfill]; }]; } else { @@ -122,11 +132,11 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; // Testing storeImage:forKey:toDisk:NO - (void)test08InsertionOfImageOnlyInMemory { XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey toDisk=NO"]; - UIImage *image = [self imageForTesting]; - [[SDImageCache sharedImageCache] storeImage:image forKey:kImageTestKey toDisk:NO completion:nil]; + UIImage *image = [self testJPEGImage]; + [[SDImageCache sharedImageCache] storeImage:image forKey:kTestImageKeyJPEG toDisk:NO completion:nil]; - expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.equal([self imageForTesting]); - [[SDImageCache sharedImageCache] diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) { + expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal([self testJPEGImage]); + [[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) { if (!isInCache) { [expectation fulfill]; } else { @@ -134,17 +144,17 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; } }]; [[SDImageCache sharedImageCache] clearMemory]; - expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.beNil(); + expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil(); [self waitForExpectationsWithCommonTimeout]; } - (void)test09RetrieveImageThroughNSOperation { XCTestExpectation *expectation = [self expectationWithDescription:@"queryCacheOperationForKey"]; - UIImage *imageForTesting = [self imageForTesting]; - [[SDImageCache sharedImageCache] storeImage:imageForTesting forKey:kImageTestKey completion:nil]; - NSOperation *operation = [[SDImageCache sharedImageCache] queryCacheOperationForKey:kImageTestKey done:^(UIImage *image, NSData *data, SDImageCacheType cacheType) { + UIImage *imageForTesting = [self testJPEGImage]; + [[SDImageCache sharedImageCache] storeImage:imageForTesting forKey:kTestImageKeyJPEG completion:nil]; + NSOperation *operation = [[SDImageCache sharedImageCache] queryCacheOperationForKey:kTestImageKeyJPEG done:^(UIImage *image, NSData *data, SDImageCacheType cacheType) { expect(image).to.equal(imageForTesting); - [[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{ + [[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{ [expectation fulfill]; }]; }]; @@ -155,10 +165,10 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test10RemoveImageForKeyWithCompletion { XCTestExpectation *expectation = [self expectationWithDescription:@"removeImageForKey"]; - [[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil]; - [[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{ - expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kImageTestKey]).to.beNil; - expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.beNil; + [[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:nil]; + [[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{ + expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kTestImageKeyJPEG]).to.beNil; + expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil; [expectation fulfill]; }]; [self waitForExpectationsWithCommonTimeout]; @@ -166,10 +176,10 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test11RemoveImageforKeyNotFromDiskWithCompletion{ XCTestExpectation *expectation = [self expectationWithDescription:@"removeImageForKey fromDisk:NO"]; - [[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil]; - [[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey fromDisk:NO withCompletion:^{ - expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kImageTestKey]).toNot.beNil; - expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.beNil; + [[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:nil]; + [[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG fromDisk:NO withCompletion:^{ + expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kTestImageKeyJPEG]).toNot.beNil; + expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil; [expectation fulfill]; }]; [self waitForExpectationsWithCommonTimeout]; @@ -177,10 +187,10 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test12RemoveImageforKeyFromDiskWithCompletion{ XCTestExpectation *expectation = [self expectationWithDescription:@"removeImageForKey fromDisk:YES"]; - [[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil]; - [[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey fromDisk:YES withCompletion:^{ - expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kImageTestKey]).to.beNil; - expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.beNil; + [[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:nil]; + [[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG fromDisk:YES withCompletion:^{ + expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kTestImageKeyJPEG]).to.beNil; + expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil; [expectation fulfill]; }]; [self waitForExpectationsWithCommonTimeout]; @@ -192,9 +202,9 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test21InitialDiskCount{ XCTestExpectation *expectation = [self expectationWithDescription:@"getDiskCount"]; - [[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:^{ + [[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:^{ expect([[SDImageCache sharedImageCache] getDiskCount]).to.equal(1); - [[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{ + [[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{ [expectation fulfill]; }]; }]; @@ -202,7 +212,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; } - (void)test31CachePathForAnyKey{ - NSString *path = [[SDImageCache sharedImageCache] cachePathForKey:kImageTestKey]; + NSString *path = [[SDImageCache sharedImageCache] cachePathForKey:kTestImageKeyJPEG]; expect(path).toNot.beNil; } @@ -213,10 +223,10 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test33CachePathForExistingKey{ XCTestExpectation *expectation = [self expectationWithDescription:@"cachePathForKey inPath"]; - [[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:^{ - NSString *path = [[SDImageCache sharedImageCache] cachePathForKey:kImageTestKey]; + [[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:^{ + NSString *path = [[SDImageCache sharedImageCache] cachePathForKey:kTestImageKeyJPEG]; expect(path).notTo.beNil; - [[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{ + [[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{ [expectation fulfill]; }]; }]; @@ -240,24 +250,24 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; - (void)test40InsertionOfImageData { XCTestExpectation *expectation = [self expectationWithDescription:@"Insertion of image data works"]; - UIImage *image = [[UIImage alloc] initWithContentsOfFile:[self testImagePath]]; + UIImage *image = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]]; NSData *imageData = UIImageJPEGRepresentation(image, 1.0); - [[SDImageCache sharedImageCache] storeImageDataToDisk:imageData forKey:kImageTestKey]; + [[SDImageCache sharedImageCache] storeImageDataToDisk:imageData forKey:kTestImageKeyJPEG]; - UIImage *storedImageFromMemory = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]; + UIImage *storedImageFromMemory = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]; expect(storedImageFromMemory).to.equal(nil); - NSString *cachePath = [[SDImageCache sharedImageCache] cachePathForKey:kImageTestKey]; + NSString *cachePath = [[SDImageCache sharedImageCache] cachePathForKey:kTestImageKeyJPEG]; UIImage *cachedImage = [[UIImage alloc] initWithContentsOfFile:cachePath]; NSData *storedImageData = UIImageJPEGRepresentation(cachedImage, 1.0); expect(storedImageData.length).to.beGreaterThan(0); expect(cachedImage.size).to.equal(image.size); // can't directly compare image and cachedImage because apparently there are some slight differences, even though the image is the same - [[SDImageCache sharedImageCache] diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) { + [[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) { expect(isInCache).to.equal(YES); - [[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{ + [[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{ [expectation fulfill]; }]; }]; @@ -315,7 +325,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; #endif - (void)test41StoreImageDataToDiskWithCustomFileManager { - NSData *imageData = [NSData dataWithContentsOfFile:[self testImagePath]]; + NSData *imageData = [NSData dataWithContentsOfFile:[self testJPEGPath]]; NSError *targetError = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteNoPermissionError userInfo:nil]; SDMockFileManager *fileManager = [[SDMockFileManager alloc] init]; @@ -327,7 +337,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; // This disk cache path creation will be mocked with error. SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"test" diskCacheDirectory:@"/" config:config]; [cache storeImageDataToDisk:imageData - forKey:kImageTestKey]; + forKey:kTestImageKeyJPEG]; expect(fileManager.lastError).equal(targetError); } @@ -352,22 +362,224 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; expect([diskCache isKindOfClass:[SDWebImageTestDiskCache class]]).to.beTruthy(); } +#pragma mark - SDWebImageCache & SDWebImageCachesManager +- (void)test50SDWebImageCacheQueryOp { + XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache query op works"]; + [[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG toDisk:NO completion:nil]; + [[SDWebImageCachesManager sharedManager] queryImageForKey:kTestImageKeyJPEG options:0 context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { + expect(image).notTo.beNil(); + [expectation fulfill]; + }]; + [self waitForExpectationsWithCommonTimeout]; +} + +- (void)test51SDWebImageCacheStoreOp { + XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache store op works"]; + [[SDWebImageCachesManager sharedManager] storeImage:[self testJPEGImage] imageData:nil forKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeAll completion:^{ + UIImage *image = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]; + expect(image).notTo.beNil(); + [[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) { + expect(isInCache).to.beTruthy(); + [expectation fulfill]; + }]; + }]; + [self waitForExpectationsWithCommonTimeout]; +} + +- (void)test52SDWebImageCacheRemoveOp { + XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache remove op works"]; + [[SDWebImageCachesManager sharedManager] removeImageForKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeDisk completion:^{ + UIImage *memoryImage = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]; + expect(memoryImage).notTo.beNil(); + [[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) { + expect(isInCache).to.beFalsy(); + [expectation fulfill]; + }]; + }]; + [self waitForExpectationsWithCommonTimeout]; +} + +- (void)test53SDWebImageCacheContainsOp { + XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache contains op works"]; + [[SDWebImageCachesManager sharedManager] containsImageForKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeAll completion:^(SDImageCacheType containsCacheType) { + expect(containsCacheType).equal(SDImageCacheTypeMemory); + [expectation fulfill]; + }]; + [self waitForExpectationsWithCommonTimeout]; +} + +- (void)test54SDWebImageCacheClearOp { + XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache clear op works"]; + [[SDWebImageCachesManager sharedManager] clearWithCacheType:SDImageCacheTypeAll completion:^{ + UIImage *memoryImage = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]; + expect(memoryImage).to.beNil(); + [[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) { + expect(isInCache).to.beFalsy(); + [expectation fulfill]; + }]; + }]; + [self waitForExpectationsWithCommonTimeout]; +} + +- (void)test55SDWebImageCachesManagerOperationPolicySimple { + SDWebImageCachesManager *cachesManager = [[SDWebImageCachesManager alloc] init]; + SDImageCache *cache1 = [[SDImageCache alloc] initWithNamespace:@"cache1"]; + SDImageCache *cache2 = [[SDImageCache alloc] initWithNamespace:@"cache2"]; + [cachesManager addCache:cache1]; + [cachesManager addCache:cache2]; + + [[NSFileManager defaultManager] removeItemAtPath:cache1.diskCachePath error:nil]; + [[NSFileManager defaultManager] removeItemAtPath:cache2.diskCachePath error:nil]; + + // LowestOnly + cachesManager.queryOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly; + cachesManager.storeOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly; + cachesManager.removeOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly; + cachesManager.containsOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly; + cachesManager.clearOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly; + [cachesManager queryImageForKey:kTestImageKeyJPEG options:0 context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { + expect(image).to.beNil(); + }]; + [cachesManager storeImage:[self testJPEGImage] imageData:nil forKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeMemory completion:nil]; + // Check Logic works, cache1 only + UIImage *memoryImage1 = [cache1 imageFromMemoryCacheForKey:kTestImageKeyJPEG]; + expect(memoryImage1).equal([self testJPEGImage]); + [cachesManager containsImageForKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeMemory completion:^(SDImageCacheType containsCacheType) { + expect(containsCacheType).equal(SDImageCacheTypeMemory); + }]; + [cachesManager removeImageForKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeMemory completion:nil]; + [cachesManager clearWithCacheType:SDImageCacheTypeMemory completion:nil]; + + // HighestOnly + cachesManager.queryOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly; + cachesManager.storeOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly; + cachesManager.removeOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly; + cachesManager.containsOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly; + cachesManager.clearOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly; + [cachesManager queryImageForKey:kTestImageKeyPNG options:0 context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { + expect(image).to.beNil(); + }]; + [cachesManager storeImage:[self testPNGImage] imageData:nil forKey:kTestImageKeyPNG cacheType:SDImageCacheTypeMemory completion:nil]; + // Check Logic works, cache2 only + UIImage *memoryImage2 = [cache2 imageFromMemoryCacheForKey:kTestImageKeyPNG]; + expect(memoryImage2).equal([self testPNGImage]); + [cachesManager containsImageForKey:kTestImageKeyPNG cacheType:SDImageCacheTypeMemory completion:^(SDImageCacheType containsCacheType) { + expect(containsCacheType).equal(SDImageCacheTypeMemory); + }]; + [cachesManager removeImageForKey:kTestImageKeyPNG cacheType:SDImageCacheTypeMemory completion:nil]; + [cachesManager clearWithCacheType:SDImageCacheTypeMemory completion:nil]; +} + +- (void)test56SDWebImageCachesManagerOperationPolicyConcurrent { + XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCachesManager operation cocurrent policy works"]; + SDWebImageCachesManager *cachesManager = [[SDWebImageCachesManager alloc] init]; + SDImageCache *cache1 = [[SDImageCache alloc] initWithNamespace:@"cache1"]; + SDImageCache *cache2 = [[SDImageCache alloc] initWithNamespace:@"cache2"]; + [cachesManager addCache:cache1]; + [cachesManager addCache:cache2]; + + [[NSFileManager defaultManager] removeItemAtPath:cache1.diskCachePath error:nil]; + [[NSFileManager defaultManager] removeItemAtPath:cache2.diskCachePath error:nil]; + + NSString *kConcurrentTestImageKey = @"kConcurrentTestImageKey"; + + // Cocurrent + // Check all concurrent op + cachesManager.queryOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent; + cachesManager.storeOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent; + cachesManager.removeOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent; + cachesManager.containsOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent; + cachesManager.clearOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent; + [cachesManager queryImageForKey:kConcurrentTestImageKey options:0 context:nil completion:nil]; + [cachesManager storeImage:[self testJPEGImage] imageData:nil forKey:kConcurrentTestImageKey cacheType:SDImageCacheTypeMemory completion:nil]; + [cachesManager removeImageForKey:kConcurrentTestImageKey cacheType:SDImageCacheTypeMemory completion:nil]; + [cachesManager clearWithCacheType:SDImageCacheTypeMemory completion:nil]; + + // Check Logic works, check cache1(memory+JPEG) & cache2(disk+PNG) at the same time. Cache1(memory) is fast and hit. + [cache1 storeImage:[self testJPEGImage] forKey:kConcurrentTestImageKey toDisk:NO completion:nil]; + [cache2 storeImage:[self testPNGImage] forKey:kConcurrentTestImageKey toDisk:YES completion:^{ + UIImage *memoryImage1 = [cache1 imageFromMemoryCacheForKey:kConcurrentTestImageKey]; + expect(memoryImage1).notTo.beNil(); + [cache2 removeImageFromMemoryForKey:kConcurrentTestImageKey]; + [cachesManager containsImageForKey:kConcurrentTestImageKey cacheType:SDImageCacheTypeAll completion:^(SDImageCacheType containsCacheType) { + // Cache1 hit + expect(containsCacheType).equal(SDImageCacheTypeMemory); + [expectation fulfill]; + }]; + }]; + + [self waitForExpectationsWithCommonTimeout]; +} + +- (void)test57SDWebImageCachesManagerOperationPolicySerial { + XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCachesManager operation serial policy works"]; + SDWebImageCachesManager *cachesManager = [[SDWebImageCachesManager alloc] init]; + SDImageCache *cache1 = [[SDImageCache alloc] initWithNamespace:@"cache1"]; + SDImageCache *cache2 = [[SDImageCache alloc] initWithNamespace:@"cache2"]; + [cachesManager addCache:cache1]; + [cachesManager addCache:cache2]; + + [[NSFileManager defaultManager] removeItemAtPath:cache1.diskCachePath error:nil]; + [[NSFileManager defaultManager] removeItemAtPath:cache2.diskCachePath error:nil]; + + NSString *kSerialTestImageKey = @"kSerialTestImageKey"; + + // Serial + // Check all serial op + cachesManager.queryOperationPolicy = SDWebImageCachesManagerOperationPolicySerial; + cachesManager.storeOperationPolicy = SDWebImageCachesManagerOperationPolicySerial; + cachesManager.removeOperationPolicy = SDWebImageCachesManagerOperationPolicySerial; + cachesManager.containsOperationPolicy = SDWebImageCachesManagerOperationPolicySerial; + cachesManager.clearOperationPolicy = SDWebImageCachesManagerOperationPolicySerial; + [cachesManager queryImageForKey:kSerialTestImageKey options:0 context:nil completion:nil]; + [cachesManager storeImage:[self testJPEGImage] imageData:nil forKey:kSerialTestImageKey cacheType:SDImageCacheTypeMemory completion:nil]; + [cachesManager removeImageForKey:kSerialTestImageKey cacheType:SDImageCacheTypeMemory completion:nil]; + [cachesManager clearWithCacheType:SDImageCacheTypeMemory completion:nil]; + + // Check Logic work, from cache2(disk+PNG) -> cache1(memory+JPEG). Cache2(disk) is slow but hit. + [cache1 storeImage:[self testJPEGImage] forKey:kSerialTestImageKey toDisk:NO completion:nil]; + [cache2 storeImage:[self testPNGImage] forKey:kSerialTestImageKey toDisk:YES completion:^{ + UIImage *memoryImage1 = [cache1 imageFromMemoryCacheForKey:kSerialTestImageKey]; + expect(memoryImage1).notTo.beNil(); + [cache2 removeImageFromMemoryForKey:kSerialTestImageKey]; + [cachesManager containsImageForKey:kSerialTestImageKey cacheType:SDImageCacheTypeAll completion:^(SDImageCacheType containsCacheType) { + // Cache2 hit + expect(containsCacheType).equal(SDImageCacheTypeDisk); + [expectation fulfill]; + }]; + }]; + + [self waitForExpectationsWithCommonTimeout]; +} + #pragma mark Helper methods -- (UIImage *)imageForTesting{ +- (UIImage *)testJPEGImage { static UIImage *reusableImage = nil; if (!reusableImage) { - reusableImage = [[UIImage alloc] initWithContentsOfFile:[self testImagePath]]; + reusableImage = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]]; } return reusableImage; } -- (NSString *)testImagePath { - +- (UIImage *)testPNGImage { + static UIImage *reusableImage = nil; + if (!reusableImage) { + reusableImage = [[UIImage alloc] initWithContentsOfFile:[self testPNGPath]]; + } + return reusableImage; +} + +- (NSString *)testJPEGPath { NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; return [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; } +- (NSString *)testPNGPath { + NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; + return [testBundle pathForResource:@"TestImage" ofType:@"png"]; +} + - (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); return [paths[0] stringByAppendingPathComponent:fullNamespace]; diff --git a/Tests/Tests/SDWebImageManagerTests.m b/Tests/Tests/SDWebImageManagerTests.m index 8ee3a567..d9887199 100644 --- a/Tests/Tests/SDWebImageManagerTests.m +++ b/Tests/Tests/SDWebImageManagerTests.m @@ -8,6 +8,7 @@ #import "SDTestCase.h" #import +#import #import "SDWebImageTestTransformer.h" @interface SDWebImageManagerTests : SDTestCase @@ -62,32 +63,6 @@ [self waitForExpectationsWithCommonTimeout]; } -- (void)test04CachedImageExistsForURL { - __block XCTestExpectation *expectation = [self expectationWithDescription:@"Image exists in cache"]; - NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; - [[SDWebImageManager sharedManager] cachedImageExistsForURL:imageURL completion:^(BOOL isInCache) { - if (isInCache) { - [expectation fulfill]; - } else { - XCTFail(@"Image should be in cache"); - } - }]; - [self waitForExpectationsWithCommonTimeout]; -} - -- (void)test05DiskImageExistsForURL { - __block XCTestExpectation *expectation = [self expectationWithDescription:@"Image exists in disk cache"]; - NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; - [[SDWebImageManager sharedManager] diskImageExistsForURL:imageURL completion:^(BOOL isInCache) { - if (isInCache) { - [expectation fulfill]; - } else { - XCTFail(@"Image should be in cache"); - } - }]; - [self waitForExpectationsWithCommonTimeout]; -} - - (void)test06CancellAll { XCTestExpectation *expectation = [self expectationWithDescription:@"Cancel"]; diff --git a/Tests/Tests/SDWebImagePrefetcherTests.m b/Tests/Tests/SDWebImagePrefetcherTests.m index 0b62a568..c6cbb3c3 100644 --- a/Tests/Tests/SDWebImagePrefetcherTests.m +++ b/Tests/Tests/SDWebImagePrefetcherTests.m @@ -8,6 +8,7 @@ */ #import "SDTestCase.h" +#import #import @interface SDWebImagePrefetcherTests : SDTestCase From 632a2bb1100699d7371e64597f156b832075b670 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 19:49:03 +0800 Subject: [PATCH 142/361] Rename all the image cache block naming with the unite naming (Prefix `SDImageCache`) --- SDWebImage/SDImageCache.h | 16 +++++++--------- SDWebImage/SDImageCache.m | 10 +++++----- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 09a04710..a1f4b971 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -46,11 +46,9 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { SDImageCachePreloadAllFrames = 1 << 6 }; -typedef void(^SDCacheQueryCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType); +typedef void(^SDImageCacheCheckCompletionBlock)(BOOL isInCache); -typedef void(^SDWebImageCheckCacheCompletionBlock)(BOOL isInCache); - -typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize); +typedef void(^SDImageCacheCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize); typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * _Nonnull key); @@ -195,7 +193,7 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * * @param completionBlock the block to be executed when the check is done. * @note the completion block will be always executed on the main queue */ -- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock; +- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDImageCacheCheckCompletionBlock)completionBlock; /** * Synchronously check if image data exists in disk cache already (does not load the image) @@ -214,7 +212,7 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * * * @return a NSOperation instance containing the cache op */ -- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock; +- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDImageCacheQueryCompletionBlock)doneBlock; /** * Asynchronously queries the cache with operation and call the completion when done. @@ -225,7 +223,7 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * * * @return a NSOperation instance containing the cache op */ -- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock; +- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDImageCacheQueryCompletionBlock)doneBlock; /** * Asynchronously queries the cache with operation and call the completion when done. @@ -237,7 +235,7 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * * * @return a NSOperation instance containing the cache op */ -- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context done:(nullable SDCacheQueryCompletedBlock)doneBlock; +- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context done:(nullable SDImageCacheQueryCompletionBlock)doneBlock; /** * Synchronously query the memory cache. @@ -327,7 +325,7 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * /** * Asynchronously calculate the disk cache's size. */ -- (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock; +- (void)calculateSizeWithCompletionBlock:(nullable SDImageCacheCalculateSizeBlock)completionBlock; @end diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 17d3ad8a..c1d8eb6b 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -226,7 +226,7 @@ #pragma mark - Query and Retrieve Ops -- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock { +- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDImageCacheCheckCompletionBlock)completionBlock { dispatch_async(self.ioQueue, ^{ BOOL exists = [self _diskImageDataExistsWithKey:key]; if (completionBlock) { @@ -358,15 +358,15 @@ } } -- (nullable NSOperation *)queryCacheOperationForKey:(NSString *)key done:(SDCacheQueryCompletedBlock)doneBlock { +- (nullable NSOperation *)queryCacheOperationForKey:(NSString *)key done:(SDImageCacheQueryCompletionBlock)doneBlock { return [self queryCacheOperationForKey:key options:0 done:doneBlock]; } -- (nullable NSOperation *)queryCacheOperationForKey:(NSString *)key options:(SDImageCacheOptions)options done:(SDCacheQueryCompletedBlock)doneBlock { +- (nullable NSOperation *)queryCacheOperationForKey:(NSString *)key options:(SDImageCacheOptions)options done:(SDImageCacheQueryCompletionBlock)doneBlock { return [self queryCacheOperationForKey:key options:options context:nil done:doneBlock]; } -- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context done:(nullable SDCacheQueryCompletedBlock)doneBlock { +- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context done:(nullable SDImageCacheQueryCompletionBlock)doneBlock { if (!key) { if (doneBlock) { doneBlock(nil, nil, SDImageCacheTypeNone); @@ -577,7 +577,7 @@ return count; } -- (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock { +- (void)calculateSizeWithCompletionBlock:(nullable SDImageCacheCalculateSizeBlock)completionBlock { dispatch_async(self.ioQueue, ^{ NSUInteger fileCount = [self.diskCache totalCount]; NSUInteger totalSize = [self.diskCache totalSize]; From 5a32da7953adfb6c5da58c6b1599aa5c7483c3c1 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 20:04:59 +0800 Subject: [PATCH 143/361] Move the complicated built-in decode process into a global function to allow user who custom web cache use it --- SDWebImage/SDImageCache.m | 47 +++++++++------------------------- SDWebImage/SDWebImageCache.h | 12 +++++++++ SDWebImage/SDWebImageCache.m | 49 ++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 35 deletions(-) diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index c1d8eb6b..dd92e8e4 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -317,41 +317,7 @@ - (nullable UIImage *)diskImageForKey:(nullable NSString *)key data:(nullable NSData *)data options:(SDImageCacheOptions)options context:(SDWebImageContext *)context { if (data) { - UIImage *image; - BOOL decodeFirstFrame = options & SDImageCacheDecodeFirstFrameOnly; - NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor]; - CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(key); - if (!decodeFirstFrame) { - // check whether we should use `SDAnimatedImage` - if ([context valueForKey:SDWebImageContextAnimatedImageClass]) { - Class animatedImageClass = [context valueForKey:SDWebImageContextAnimatedImageClass]; - if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { - image = [[animatedImageClass alloc] initWithData:data scale:scale]; - if (options & SDImageCachePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { - [((id)image) preloadAllFrames]; - } - } - } - } - if (!image) { - image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; - } - BOOL shouldDecode = (options & SDImageCacheAvoidDecodeImage) == 0; - if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { - // `SDAnimatedImage` do not decode - shouldDecode = NO; - } else if (image.sd_isAnimated) { - // animated image do not decode - shouldDecode = NO; - } - if (shouldDecode) { - BOOL shouldScaleDown = options & SDImageCacheScaleDownLargeImages; - if (shouldScaleDown) { - image = [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; - } else { - image = [SDWebImageCoderHelper decodedImageWithImage:image]; - } - } + UIImage *image = SDWebImageCacheDecodeImageData(data, key, [[self class] imageOptionsFromCacheOptions:options], context); return image; } else { return nil; @@ -589,6 +555,17 @@ }); } +#pragma mark - Helper ++ (SDWebImageOptions)imageOptionsFromCacheOptions:(SDImageCacheOptions)cacheOptions { + SDWebImageOptions options = 0; + if (cacheOptions & SDImageCacheScaleDownLargeImages) options |= SDWebImageScaleDownLargeImages; + if (cacheOptions & SDImageCacheDecodeFirstFrameOnly) options |= SDWebImageDecodeFirstFrameOnly; + if (cacheOptions & SDImageCachePreloadAllFrames) options |= SDWebImagePreloadAllFrames; + if (cacheOptions & SDImageCacheAvoidDecodeImage) options |= SDWebImageAvoidDecodeImage; + + return options; +} + @end @implementation SDImageCache (SDWebImageCache) diff --git a/SDWebImage/SDWebImageCache.h b/SDWebImage/SDWebImageCache.h index ed101362..c5aeb0b4 100644 --- a/SDWebImage/SDWebImageCache.h +++ b/SDWebImage/SDWebImageCache.h @@ -37,6 +37,18 @@ typedef NS_ENUM(NSInteger, SDImageCacheType) { typedef void(^SDImageCacheQueryCompletionBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType); typedef void(^SDImageCacheContainsCompletionBlock)(SDImageCacheType containsCacheType); +/** + This is the built-in decoding process for image query from cache. + @note If you want to implement your custom loader with `queryImageForKey:options:context:completion:` API, but also want to keep compatible with SDWebImage's behavior, you'd better use this to produce image. + + @param imageData The image data from the cache. Should not be nil + @param cacheKey The image cache key from the input. Should not be nil + @param options The options arg from the input + @param context The context arg from the input + @return The decoded image for current image data query from cache + */ +FOUNDATION_EXPORT UIImage * _Nullable SDWebImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context); + /** This is the image cache protocol to provide custom image cache for `SDWebImageManager`. Though the best practice to custom image cache, is to write your own class which conform `SDMemoryCache` or `SDDiskCache` protocol for `SDImageCache` class (See more on `SDImageCacheConfig.memoryCacheClass & SDImageCacheConfig.diskCacheClass`). diff --git a/SDWebImage/SDWebImageCache.m b/SDWebImage/SDWebImageCache.m index 8203e7bd..bfd67063 100644 --- a/SDWebImage/SDWebImageCache.m +++ b/SDWebImage/SDWebImageCache.m @@ -7,3 +7,52 @@ */ #import "SDWebImageCache.h" +#import "SDWebImageCodersManager.h" +#import "SDWebImageCoderHelper.h" +#import "SDAnimatedImage.h" +#import "UIImage+WebCache.h" + +UIImage * _Nullable SDWebImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context) { + UIImage *image; + BOOL decodeFirstFrame = options & SDWebImageDecodeFirstFrameOnly; + NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor]; + CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); + if (scale < 1) { + scale = 1; + } + if (!decodeFirstFrame) { + // check whether we should use `SDAnimatedImage` + if ([context valueForKey:SDWebImageContextAnimatedImageClass]) { + Class animatedImageClass = [context valueForKey:SDWebImageContextAnimatedImageClass]; + if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { + image = [[animatedImageClass alloc] initWithData:imageData scale:scale]; + if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { + [((id)image) preloadAllFrames]; + } + } + } + } + if (!image) { + image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; + } + if (image) { + BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; + if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { + // `SDAnimatedImage` do not decode + shouldDecode = NO; + } else if (image.sd_isAnimated) { + // animated image do not decode + shouldDecode = NO; + } + if (shouldDecode) { + BOOL shouldScaleDown = options & SDWebImageScaleDownLargeImages; + if (shouldScaleDown) { + image = [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; + } else { + image = [SDWebImageCoderHelper decodedImageWithImage:image]; + } + } + } + + return image; +} From bee542507821a1b84efc51b67c6281548fc44122 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 18 Apr 2018 19:05:10 +0800 Subject: [PATCH 144/361] Rename the caches manager without `Web` prefix --- SDWebImage.xcodeproj/project.pbxproj | 56 +++++------ ...CachesManager.h => SDImageCachesManager.h} | 24 ++--- ...CachesManager.m => SDImageCachesManager.m} | 92 +++++++++---------- 3 files changed, 86 insertions(+), 86 deletions(-) rename SDWebImage/{SDWebImageCachesManager.h => SDImageCachesManager.h} (59%) rename SDWebImage/{SDWebImageCachesManager.m => SDImageCachesManager.m} (85%) diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 11e46035..695866a7 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -520,18 +520,18 @@ 32D122272080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; 32D122282080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; 32D122292080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; - 32D1222A2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; }; - 32D1222B2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; }; - 32D1222C2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; }; - 32D1222D2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; }; - 32D1222E2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; }; - 32D1222F2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; }; - 32D122302080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122312080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122322080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122332080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122342080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122352080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D1222A2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; + 32D1222B2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; + 32D1222C2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; + 32D1222D2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; + 32D1222E2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; + 32D1222F2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; + 32D122302080B2EB003685A3 /* SDImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122312080B2EB003685A3 /* SDImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122322080B2EB003685A3 /* SDImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122332080B2EB003685A3 /* SDImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122342080B2EB003685A3 /* SDImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122352080B2EB003685A3 /* SDImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32EB6D8E206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; 32EB6D8F206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; 32EB6D90206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; }; @@ -1598,8 +1598,8 @@ 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCoderHelper.m; sourceTree = ""; }; 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageCache.h; sourceTree = ""; }; 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCache.m; sourceTree = ""; }; - 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCachesManager.m; sourceTree = ""; }; - 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageCachesManager.h; sourceTree = ""; }; + 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageCachesManager.m; sourceTree = ""; }; + 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageCachesManager.h; sourceTree = ""; }; 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderRequestModifier.h; sourceTree = ""; }; 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderRequestModifier.m; sourceTree = ""; }; 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTransformer.h; sourceTree = ""; }; @@ -2120,8 +2120,8 @@ 328BB6BE2082581100760D6C /* SDDiskCache.m */, 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */, 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */, - 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */, - 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */, + 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */, + 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */, ); name = Cache; sourceTree = ""; @@ -2412,7 +2412,7 @@ 3248476C201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 80377C5F1F2F666300F89830 /* utils.h in Headers */, 80377C5B1F2F666300F89830 /* rescaler_utils.h in Headers */, - 32D122332080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */, + 32D122332080B2EB003685A3 /* SDImageCachesManager.h in Headers */, 323F8BF91F38EF770092B609 /* animi.h in Headers */, 32F7C0872030719600873181 /* UIImage+Transform.h in Headers */, 80377C4F1F2F666300F89830 /* filters_utils.h in Headers */, @@ -2482,7 +2482,7 @@ 80377C271F2F666300F89830 /* rescaler_utils.h in Headers */, 323F8B511F38EF770092B609 /* backward_references_enc.h in Headers */, 325312C9200F09910046BF1E /* SDWebImageTransition.h in Headers */, - 32D122312080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */, + 32D122312080B2EB003685A3 /* SDImageCachesManager.h in Headers */, 43A918651D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 4314D1741D0E0E3B004B36C9 /* types.h in Headers */, 4314D1761D0E0E3B004B36C9 /* decode.h in Headers */, @@ -2564,7 +2564,7 @@ 80377E211F2F66A800F89830 /* neon.h in Headers */, 80377C711F2F666400F89830 /* quant_levels_utils.h in Headers */, 323F8B541F38EF770092B609 /* backward_references_enc.h in Headers */, - 32D122342080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */, + 32D122342080B2EB003685A3 /* SDImageCachesManager.h in Headers */, 32F7C0882030719600873181 /* UIImage+Transform.h in Headers */, 43A62A1F1D0E0A800089D7DD /* mux.h in Headers */, 431BB6E91D06D2C1006A3455 /* SDWebImageDownloaderOperation.h in Headers */, @@ -2700,7 +2700,7 @@ 321E608B1F38E8C800405457 /* SDWebImageCoder.h in Headers */, 323F8B731F38EF770092B609 /* delta_palettization_enc.h in Headers */, 321E60C31F38E91700405457 /* UIImage+ForceDecode.h in Headers */, - 32D122352080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */, + 32D122352080B2EB003685A3 /* SDImageCachesManager.h in Headers */, 32484768201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80377E561F2F66A800F89830 /* lossless_common.h in Headers */, 4397D2E91D0DDD8C00BB2784 /* UIImage+WebP.h in Headers */, @@ -2799,7 +2799,7 @@ 3248476B201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 4A2CAE311AB4BB7500B6BC39 /* UIImage+WebP.h in Headers */, 323F8BF81F38EF770092B609 /* animi.h in Headers */, - 32D122322080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */, + 32D122322080B2EB003685A3 /* SDImageCachesManager.h in Headers */, 80377C351F2F666300F89830 /* filters_utils.h in Headers */, 32F7C0862030719600873181 /* UIImage+Transform.h in Headers */, 80377C321F2F666300F89830 /* color_cache_utils.h in Headers */, @@ -2853,7 +2853,7 @@ 431738BD1CDFC2660008FEB9 /* decode.h in Headers */, 80377D0B1F2F66A100F89830 /* mips_macro.h in Headers */, 329A18591FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, - 32D122302080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */, + 32D122302080B2EB003685A3 /* SDImageCachesManager.h in Headers */, 5376131A155AD0D5005750A4 /* SDWebImageDownloader.h in Headers */, 328BB6CD2082581100760D6C /* SDMemoryCache.h in Headers */, 4369C2771D9807EC007E863A /* UIView+WebCache.h in Headers */, @@ -3218,7 +3218,7 @@ 80377DDE1F2F66A700F89830 /* rescaler_mips32.c in Sources */, 80377DCA1F2F66A700F89830 /* filters_sse2.c in Sources */, 80377EBE1F2F66D500F89830 /* quant_dec.c in Sources */, - 32D1222D2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */, + 32D1222D2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, 80377DB61F2F66A700F89830 /* dec_clip_tables.c in Sources */, 80377C5E1F2F666300F89830 /* utils.c in Sources */, 32B9B540206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, @@ -3389,7 +3389,7 @@ 80377D2F1F2F66A700F89830 /* dec_msa.c in Sources */, 323F8C151F38EF770092B609 /* muxinternal.c in Sources */, 80377D571F2F66A700F89830 /* rescaler_sse2.c in Sources */, - 32D1222B2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */, + 32D1222B2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, 43C892A11D9D6DDC0022038D /* demux.c in Sources */, 80377C131F2F666300F89830 /* bit_reader_utils.c in Sources */, 80377E9C1F2F66D400F89830 /* idec_dec.c in Sources */, @@ -3553,7 +3553,7 @@ 323F8BBE1F38EF770092B609 /* predictor_enc.c in Sources */, 80377E261F2F66A800F89830 /* rescaler_sse2.c in Sources */, 323F8C181F38EF770092B609 /* muxinternal.c in Sources */, - 32D1222E2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */, + 32D1222E2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, 80377C741F2F666400F89830 /* rescaler_utils.c in Sources */, 431BB6B11D06D2C1006A3455 /* UIView+WebCacheOperation.m in Sources */, 80377DF01F2F66A800F89830 /* alpha_processing_sse41.c in Sources */, @@ -3692,7 +3692,7 @@ 321E60C91F38E91700405457 /* UIImage+ForceDecode.m in Sources */, 80377E551F2F66A800F89830 /* filters.c in Sources */, 80377E731F2F66A800F89830 /* yuv_mips32.c in Sources */, - 32D1222F2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */, + 32D1222F2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, 4397D2911D0DDD8C00BB2784 /* MKAnnotationView+WebCache.m in Sources */, 4397D2921D0DDD8C00BB2784 /* SDWebImagePrefetcher.m in Sources */, 323F8BBF1F38EF770092B609 /* predictor_enc.c in Sources */, @@ -3880,7 +3880,7 @@ 80377C441F2F666300F89830 /* utils.c in Sources */, 80377D8D1F2F66A700F89830 /* lossless_enc_sse41.c in Sources */, 80377EAE1F2F66D400F89830 /* quant_dec.c in Sources */, - 32D1222C2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */, + 32D1222C2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, 80377D6E1F2F66A700F89830 /* cost_sse2.c in Sources */, 80377D991F2F66A700F89830 /* rescaler_mips32.c in Sources */, 32B9B53F206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, @@ -4048,7 +4048,7 @@ 80377D031F2F66A100F89830 /* lossless_enc_sse41.c in Sources */, 80377E8E1F2F66D000F89830 /* quant_dec.c in Sources */, 80377CE41F2F66A100F89830 /* cost_sse2.c in Sources */, - 32D1222A2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */, + 32D1222A2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, 80377D0F1F2F66A100F89830 /* rescaler_mips32.c in Sources */, 323F8C081F38EF770092B609 /* muxedit.c in Sources */, 32B9B53D206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, diff --git a/SDWebImage/SDWebImageCachesManager.h b/SDWebImage/SDImageCachesManager.h similarity index 59% rename from SDWebImage/SDWebImageCachesManager.h rename to SDWebImage/SDImageCachesManager.h index c7f508dc..f6aabb62 100644 --- a/SDWebImage/SDWebImageCachesManager.h +++ b/SDWebImage/SDImageCachesManager.h @@ -9,19 +9,19 @@ #import #import "SDWebImageCache.h" -typedef NS_ENUM(NSUInteger, SDWebImageCachesManagerOperationPolicy) { - SDWebImageCachesManagerOperationPolicySerial, // process all caches serially (from the highest priority to the lowest priority cache by order) - SDWebImageCachesManagerOperationPolicyConcurrent, // process all caches concurrently - SDWebImageCachesManagerOperationPolicyHighestOnly, // process the highest priority cache only - SDWebImageCachesManagerOperationPolicyLowestOnly // process the lowest priority cache only +typedef NS_ENUM(NSUInteger, SDImageCachesManagerOperationPolicy) { + SDImageCachesManagerOperationPolicySerial, // process all caches serially (from the highest priority to the lowest priority cache by order) + SDImageCachesManagerOperationPolicyConcurrent, // process all caches concurrently + SDImageCachesManagerOperationPolicyHighestOnly, // process the highest priority cache only + SDImageCachesManagerOperationPolicyLowestOnly // process the lowest priority cache only }; -@interface SDWebImageCachesManager : NSObject +@interface SDImageCachesManager : NSObject /** Returns the global shared caches manager instance. */ -@property (nonatomic, class, readonly, nonnull) SDWebImageCachesManager *sharedManager; +@property (nonatomic, class, readonly, nonnull) SDImageCachesManager *sharedManager; // These are op policy for cache manager. @@ -29,31 +29,31 @@ typedef NS_ENUM(NSUInteger, SDWebImageCachesManagerOperationPolicy) { Operation policy for query op. Defaults to `Serial`, means query all caches serially (one completion called then next begin) until one cache query success (`image` != nil). */ -@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy queryOperationPolicy; +@property (nonatomic, assign) SDImageCachesManagerOperationPolicy queryOperationPolicy; /** Operation policy for store op. Defaults to `HighestOnly`, means store to the highest priority cache only. */ -@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy storeOperationPolicy; +@property (nonatomic, assign) SDImageCachesManagerOperationPolicy storeOperationPolicy; /** Operation policy for remove op. Defaults to `Concurrent`, means remove all caches concurrently. */ -@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy removeOperationPolicy; +@property (nonatomic, assign) SDImageCachesManagerOperationPolicy removeOperationPolicy; /** Operation policy for contains op. Defaults to `Serial`, means check all caches serially (one completion called then next begin) until one cache check success (`containsCacheType` != None). */ -@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy containsOperationPolicy; +@property (nonatomic, assign) SDImageCachesManagerOperationPolicy containsOperationPolicy; /** Operation policy for clear op. Defaults to `Concurrent`, means clear all caches concurrently. */ -@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy clearOperationPolicy; +@property (nonatomic, assign) SDImageCachesManagerOperationPolicy clearOperationPolicy; /** All caches in caches manager. The caches array is a priority queue, which means the later added cache will have the highest priority diff --git a/SDWebImage/SDWebImageCachesManager.m b/SDWebImage/SDImageCachesManager.m similarity index 85% rename from SDWebImage/SDWebImageCachesManager.m rename to SDWebImage/SDImageCachesManager.m index e7644774..2b26f229 100644 --- a/SDWebImage/SDWebImageCachesManager.m +++ b/SDWebImage/SDImageCachesManager.m @@ -6,10 +6,10 @@ * file that was distributed with this source code. */ -#import "SDWebImageCachesManager.h" +#import "SDImageCachesManager.h" // This is used for operation management, but not for operation queue execute -@interface SDWebImageCachesManagerOperation : NSOperation +@interface SDImageCachesManagerOperation : NSOperation @property (nonatomic, assign, readonly) NSUInteger pendingCount; @@ -19,7 +19,7 @@ @end -@implementation SDWebImageCachesManagerOperation +@implementation SDImageCachesManagerOperation @synthesize executing = _executing; @synthesize finished = _finished; @@ -70,13 +70,13 @@ @end -@implementation SDWebImageCachesManager +@implementation SDImageCachesManager -+ (SDWebImageCachesManager *)sharedManager { ++ (SDImageCachesManager *)sharedManager { static dispatch_once_t onceToken; - static SDWebImageCachesManager *manager; + static SDImageCachesManager *manager; dispatch_once(&onceToken, ^{ - manager = [[SDWebImageCachesManager alloc] init]; + manager = [[SDImageCachesManager alloc] init]; }); return manager; } @@ -84,11 +84,11 @@ - (instancetype)init { self = [super init]; if (self) { - self.queryOperationPolicy = SDWebImageCachesManagerOperationPolicySerial; - self.storeOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly; - self.removeOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent; - self.containsOperationPolicy = SDWebImageCachesManagerOperationPolicySerial; - self.clearOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent; + self.queryOperationPolicy = SDImageCachesManagerOperationPolicySerial; + self.storeOperationPolicy = SDImageCachesManagerOperationPolicyHighestOnly; + self.removeOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; + self.containsOperationPolicy = SDImageCachesManagerOperationPolicySerial; + self.clearOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; } return self; } @@ -130,25 +130,25 @@ return [caches.firstObject queryImageForKey:key options:options context:context completion:completionBlock]; } switch (self.queryOperationPolicy) { - case SDWebImageCachesManagerOperationPolicyHighestOnly: { + case SDImageCachesManagerOperationPolicyHighestOnly: { id cache = caches.lastObject; return [cache queryImageForKey:key options:options context:context completion:completionBlock]; } break; - case SDWebImageCachesManagerOperationPolicyLowestOnly: { + case SDImageCachesManagerOperationPolicyLowestOnly: { id cache = caches.firstObject; return [cache queryImageForKey:key options:options context:context completion:completionBlock]; } break; - case SDWebImageCachesManagerOperationPolicyConcurrent: { - SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new]; + case SDImageCachesManagerOperationPolicyConcurrent: { + SDImageCachesManagerOperation *operation = [SDImageCachesManagerOperation new]; [operation beginWithTotalCount:caches.count]; [self concurrentQueryImageForKey:key options:options context:context completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; return operation; } break; - case SDWebImageCachesManagerOperationPolicySerial: { - SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new]; + case SDImageCachesManagerOperationPolicySerial: { + SDImageCachesManagerOperation *operation = [SDImageCachesManagerOperation new]; [operation beginWithTotalCount:caches.count]; [self serialQueryImageForKey:key options:options context:context completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; return operation; @@ -173,23 +173,23 @@ return; } switch (self.storeOperationPolicy) { - case SDWebImageCachesManagerOperationPolicyHighestOnly: { + case SDImageCachesManagerOperationPolicyHighestOnly: { id cache = caches.lastObject; [cache storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock]; } break; - case SDWebImageCachesManagerOperationPolicyLowestOnly: { + case SDImageCachesManagerOperationPolicyLowestOnly: { id cache = caches.firstObject; [cache storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock]; } break; - case SDWebImageCachesManagerOperationPolicyConcurrent: { - SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new]; + case SDImageCachesManagerOperationPolicyConcurrent: { + SDImageCachesManagerOperation *operation = [SDImageCachesManagerOperation new]; [operation beginWithTotalCount:caches.count]; [self concurrentStoreImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; } break; - case SDWebImageCachesManagerOperationPolicySerial: { + case SDImageCachesManagerOperationPolicySerial: { [self serialStoreImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator]; } break; @@ -211,23 +211,23 @@ return; } switch (self.removeOperationPolicy) { - case SDWebImageCachesManagerOperationPolicyHighestOnly: { + case SDImageCachesManagerOperationPolicyHighestOnly: { id cache = caches.lastObject; [cache removeImageForKey:key cacheType:cacheType completion:completionBlock]; } break; - case SDWebImageCachesManagerOperationPolicyLowestOnly: { + case SDImageCachesManagerOperationPolicyLowestOnly: { id cache = caches.firstObject; [cache removeImageForKey:key cacheType:cacheType completion:completionBlock]; } break; - case SDWebImageCachesManagerOperationPolicyConcurrent: { - SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new]; + case SDImageCachesManagerOperationPolicyConcurrent: { + SDImageCachesManagerOperation *operation = [SDImageCachesManagerOperation new]; [operation beginWithTotalCount:caches.count]; [self concurrentRemoveImageForKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; } break; - case SDWebImageCachesManagerOperationPolicySerial: { + case SDImageCachesManagerOperationPolicySerial: { [self serialRemoveImageForKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator]; } break; @@ -249,24 +249,24 @@ return; } switch (self.clearOperationPolicy) { - case SDWebImageCachesManagerOperationPolicyHighestOnly: { + case SDImageCachesManagerOperationPolicyHighestOnly: { id cache = caches.lastObject; [cache containsImageForKey:key cacheType:cacheType completion:completionBlock]; } break; - case SDWebImageCachesManagerOperationPolicyLowestOnly: { + case SDImageCachesManagerOperationPolicyLowestOnly: { id cache = caches.firstObject; [cache containsImageForKey:key cacheType:cacheType completion:completionBlock]; } break; - case SDWebImageCachesManagerOperationPolicyConcurrent: { - SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new]; + case SDImageCachesManagerOperationPolicyConcurrent: { + SDImageCachesManagerOperation *operation = [SDImageCachesManagerOperation new]; [operation beginWithTotalCount:caches.count]; [self concurrentContainsImageForKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; } break; - case SDWebImageCachesManagerOperationPolicySerial: { - SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new]; + case SDImageCachesManagerOperationPolicySerial: { + SDImageCachesManagerOperation *operation = [SDImageCachesManagerOperation new]; [operation beginWithTotalCount:caches.count]; [self serialContainsImageForKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; } @@ -286,23 +286,23 @@ return; } switch (self.clearOperationPolicy) { - case SDWebImageCachesManagerOperationPolicyHighestOnly: { + case SDImageCachesManagerOperationPolicyHighestOnly: { id cache = caches.lastObject; [cache clearWithCacheType:cacheType completion:completionBlock]; } break; - case SDWebImageCachesManagerOperationPolicyLowestOnly: { + case SDImageCachesManagerOperationPolicyLowestOnly: { id cache = caches.firstObject; [cache clearWithCacheType:cacheType completion:completionBlock]; } break; - case SDWebImageCachesManagerOperationPolicyConcurrent: { - SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new]; + case SDImageCachesManagerOperationPolicyConcurrent: { + SDImageCachesManagerOperation *operation = [SDImageCachesManagerOperation new]; [operation beginWithTotalCount:caches.count]; [self concurrentClearWithCacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; } break; - case SDWebImageCachesManagerOperationPolicySerial: { + case SDImageCachesManagerOperationPolicySerial: { [self serialClearWithCacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator]; } break; @@ -313,7 +313,7 @@ #pragma mark - Concurrent Operation -- (void)concurrentQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation { +- (void)concurrentQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); for (id cache in enumerator) { @@ -346,7 +346,7 @@ } } -- (void)concurrentStoreImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation { +- (void)concurrentStoreImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); for (id cache in enumerator) { @@ -371,7 +371,7 @@ } } -- (void)concurrentRemoveImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation { +- (void)concurrentRemoveImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); for (id cache in enumerator) { @@ -396,7 +396,7 @@ } } -- (void)concurrentContainsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheContainsCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation { +- (void)concurrentContainsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheContainsCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); for (id cache in enumerator) { @@ -429,7 +429,7 @@ } } -- (void)concurrentClearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation { +- (void)concurrentClearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); for (id cache in enumerator) { @@ -456,7 +456,7 @@ #pragma mark - Serial Operation -- (void)serialQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation { +- (void)serialQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); id cache = enumerator.nextObject; @@ -526,7 +526,7 @@ }]; } -- (void)serialContainsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheContainsCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation { +- (void)serialContainsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheContainsCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); id cache = enumerator.nextObject; From 734c6821d5a55f988f1a28192b3ac347cba5cd2f Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 18 Apr 2018 19:16:45 +0800 Subject: [PATCH 145/361] Rename the cache protocol to `SDImageCache` protocol --- SDWebImage.xcodeproj/project.pbxproj | 56 ++++++------- SDWebImage/SDImageCache.h | 12 +-- ...SDWebImageCache.h => SDImageCacheDefine.h} | 5 +- ...SDWebImageCache.m => SDImageCacheDefine.m} | 2 +- SDWebImage/SDImageCachesManager.h | 10 +-- SDWebImage/SDImageCachesManager.m | 82 +++++++++---------- SDWebImage/SDWebImageManager.h | 8 +- SDWebImage/SDWebImageManager.m | 12 +-- 8 files changed, 92 insertions(+), 95 deletions(-) rename SDWebImage/{SDWebImageCache.h => SDImageCacheDefine.h} (95%) rename SDWebImage/{SDWebImageCache.m => SDImageCacheDefine.m} (98%) diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 695866a7..ee9d0625 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -508,18 +508,18 @@ 32CF1C101FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; 32CF1C111FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; 32CF1C121FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; - 32D1221E2080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D1221F2080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122202080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122212080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122222080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122232080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32D122242080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; - 32D122252080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; - 32D122262080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; - 32D122272080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; - 32D122282080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; - 32D122292080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; }; + 32D1221E2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D1221F2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122202080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122212080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122222080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122232080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32D122242080B2EB003685A3 /* SDImageCacheDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */; }; + 32D122252080B2EB003685A3 /* SDImageCacheDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */; }; + 32D122262080B2EB003685A3 /* SDImageCacheDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */; }; + 32D122272080B2EB003685A3 /* SDImageCacheDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */; }; + 32D122282080B2EB003685A3 /* SDImageCacheDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */; }; + 32D122292080B2EB003685A3 /* SDImageCacheDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */; }; 32D1222A2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; 32D1222B2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; 32D1222C2080B2EB003685A3 /* SDImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */; }; @@ -1596,8 +1596,8 @@ 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageIndicator.m; sourceTree = ""; }; 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoderHelper.h; sourceTree = ""; }; 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCoderHelper.m; sourceTree = ""; }; - 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageCache.h; sourceTree = ""; }; - 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCache.m; sourceTree = ""; }; + 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageCacheDefine.h; sourceTree = ""; }; + 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageCacheDefine.m; sourceTree = ""; }; 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageCachesManager.m; sourceTree = ""; }; 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageCachesManager.h; sourceTree = ""; }; 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderRequestModifier.h; sourceTree = ""; }; @@ -2118,8 +2118,8 @@ 328BB6C02082581100760D6C /* SDMemoryCache.m */, 328BB6BD2082581100760D6C /* SDDiskCache.h */, 328BB6BE2082581100760D6C /* SDDiskCache.m */, - 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */, - 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */, + 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */, + 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */, 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */, 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */, ); @@ -2342,7 +2342,7 @@ 323F8B531F38EF770092B609 /* backward_references_enc.h in Headers */, 4317395A1CDFC8B70008FEB9 /* mux_types.h in Headers */, 431739561CDFC8B70008FEB9 /* demux.h in Headers */, - 32D122212080B2EB003685A3 /* SDWebImageCache.h in Headers */, + 32D122212080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 32B9B53A206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AD2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 80377C4A1F2F666300F89830 /* bit_writer_utils.h in Headers */, @@ -2440,7 +2440,7 @@ 80377C1D1F2F666300F89830 /* huffman_encode_utils.h in Headers */, 321E60B11F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 80377E9A1F2F66D400F89830 /* common_dec.h in Headers */, - 32D1221F2080B2EB003685A3 /* SDWebImageCache.h in Headers */, + 32D1221F2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 327054D5206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, 328BB6AB2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 32B9B538206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, @@ -2609,7 +2609,7 @@ 32F7C0732030114C00873181 /* SDWebImageTransformer.h in Headers */, 431BB6FA1D06D2C1006A3455 /* SDWebImageDownloader.h in Headers */, 3248476D201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, - 32D122222080B2EB003685A3 /* SDWebImageCache.h in Headers */, + 32D122222080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 80377DF51F2F66A800F89830 /* common_sse2.h in Headers */, 323F8BDC1F38EF770092B609 /* vp8i_enc.h in Headers */, 80377ED21F2F66D500F89830 /* vp8i_dec.h in Headers */, @@ -2630,7 +2630,7 @@ 32F7C0892030719600873181 /* UIImage+Transform.h in Headers */, 80377EDA1F2F66D500F89830 /* common_dec.h in Headers */, 80377EE61F2F66D500F89830 /* webpi_dec.h in Headers */, - 32D122232080B2EB003685A3 /* SDWebImageCache.h in Headers */, + 32D122232080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 32B9B53C206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AF2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 4397D2BA1D0DDD8C00BB2784 /* demux.h in Headers */, @@ -2729,7 +2729,7 @@ 323F8B521F38EF770092B609 /* backward_references_enc.h in Headers */, 4317394F1CDFC8B70008FEB9 /* demux.h in Headers */, 43CE757D1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, - 32D122202080B2EB003685A3 /* SDWebImageCache.h in Headers */, + 32D122202080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AC2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 80377C301F2F666300F89830 /* bit_writer_utils.h in Headers */, @@ -2901,7 +2901,7 @@ 323F8B6E1F38EF770092B609 /* delta_palettization_enc.h in Headers */, 438096721CDFC08200DC626B /* MKAnnotationView+WebCache.h in Headers */, 43CE757C1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, - 32D1221E2080B2EB003685A3 /* SDWebImageCache.h in Headers */, + 32D1221E2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 80377E8A1F2F66D000F89830 /* common_dec.h in Headers */, AB615303192DA24600A2D8E9 /* UIView+WebCacheOperation.h in Headers */, 323F8B501F38EF770092B609 /* backward_references_enc.h in Headers */, @@ -3261,7 +3261,7 @@ 80377DB51F2F66A700F89830 /* cpu.c in Sources */, 80377EC51F2F66D500F89830 /* webp_dec.c in Sources */, 80377DD61F2F66A700F89830 /* lossless_neon.c in Sources */, - 32D122272080B2EB003685A3 /* SDWebImageCache.m in Sources */, + 32D122272080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, 00733A5C1BC4880000A5A117 /* UIButton+WebCache.m in Sources */, 80377EC01F2F66D500F89830 /* vp8_dec.c in Sources */, 80377C521F2F666300F89830 /* huffman_utils.c in Sources */, @@ -3345,7 +3345,7 @@ 4314D1341D0E0E3B004B36C9 /* UIImage+WebP.m in Sources */, 80377D3D1F2F66A700F89830 /* filters_mips_dsp_r2.c in Sources */, 323F8B751F38EF770092B609 /* filter_enc.c in Sources */, - 32D122252080B2EB003685A3 /* SDWebImageCache.m in Sources */, + 32D122252080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, 80377D401F2F66A700F89830 /* filters_sse2.c in Sources */, 80377D1E1F2F66A700F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, 80377D291F2F66A700F89830 /* cost_sse2.c in Sources */, @@ -3509,7 +3509,7 @@ 323F8BE21F38EF770092B609 /* vp8l_enc.c in Sources */, 431BB6A31D06D2C1006A3455 /* UIImageView+WebCache.m in Sources */, 80377E0C1F2F66A800F89830 /* filters_mips_dsp_r2.c in Sources */, - 32D122282080B2EB003685A3 /* SDWebImageCache.m in Sources */, + 32D122282080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, 323F8B781F38EF770092B609 /* filter_enc.c in Sources */, 4369C2821D9807EC007E863A /* UIView+WebCache.m in Sources */, 80377E0F1F2F66A800F89830 /* filters_sse2.c in Sources */, @@ -3705,7 +3705,7 @@ 80377E381F2F66A800F89830 /* argb_sse2.c in Sources */, 323F8B9B1F38EF770092B609 /* near_lossless_enc.c in Sources */, 32F21B5C20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, - 32D122292080B2EB003685A3 /* SDWebImageCache.m in Sources */, + 32D122292080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, 80377E3B1F2F66A800F89830 /* cost_mips_dsp_r2.c in Sources */, 4397D29B1D0DDD8C00BB2784 /* SDWebImageDownloader.m in Sources */, 80377E711F2F66A800F89830 /* upsampling.c in Sources */, @@ -3923,7 +3923,7 @@ 80377D8C1F2F66A700F89830 /* lossless_enc_sse2.c in Sources */, 4A2CAE2C1AB4BB7500B6BC39 /* UIButton+WebCache.m in Sources */, 80377EB51F2F66D400F89830 /* webp_dec.c in Sources */, - 32D122262080B2EB003685A3 /* SDWebImageCache.m in Sources */, + 32D122262080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, 80377D701F2F66A700F89830 /* cpu.c in Sources */, 80377D911F2F66A700F89830 /* lossless_neon.c in Sources */, 80377EB01F2F66D400F89830 /* vp8_dec.c in Sources */, @@ -4091,7 +4091,7 @@ A18A6CC9172DC28500419892 /* UIImage+GIF.m in Sources */, 80377E951F2F66D000F89830 /* webp_dec.c in Sources */, 80377CE61F2F66A100F89830 /* cpu.c in Sources */, - 32D122242080B2EB003685A3 /* SDWebImageCache.m in Sources */, + 32D122242080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, 80377D071F2F66A100F89830 /* lossless_neon.c in Sources */, 80377E901F2F66D000F89830 /* vp8_dec.c in Sources */, 80377C041F2F665300F89830 /* huffman_utils.c in Sources */, diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index a1f4b971..e70c280f 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -10,7 +10,7 @@ #import "SDWebImageCompat.h" #import "SDWebImageDefine.h" #import "SDImageCacheConfig.h" -#import "SDWebImageCache.h" +#import "SDImageCacheDefine.h" typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { /** @@ -46,14 +46,8 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { SDImageCachePreloadAllFrames = 1 << 6 }; -typedef void(^SDImageCacheCheckCompletionBlock)(BOOL isInCache); - -typedef void(^SDImageCacheCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize); - -typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * _Nonnull key); - /** - * SDImageCache maintains a memory cache and an optional disk cache. Disk cache write operations are performed + * SDImageCache maintains a memory cache and a disk cache. Disk cache write operations are performed * asynchronous so it doesn’t add unnecessary latency to the UI. */ @interface SDImageCache : NSObject @@ -332,6 +326,6 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * /** * SDImageCache is the built-in image cache implementation for web image manager. It adopts `SDWebImageCache` protocol to provide the function for web image manager to use for image loading process. */ -@interface SDImageCache (SDWebImageCache) +@interface SDImageCache (SDWebImageCache) @end diff --git a/SDWebImage/SDWebImageCache.h b/SDWebImage/SDImageCacheDefine.h similarity index 95% rename from SDWebImage/SDWebImageCache.h rename to SDWebImage/SDImageCacheDefine.h index c5aeb0b4..caf186ed 100644 --- a/SDWebImage/SDWebImageCache.h +++ b/SDWebImage/SDImageCacheDefine.h @@ -34,6 +34,9 @@ typedef NS_ENUM(NSInteger, SDImageCacheType) { SDImageCacheTypeAll }; +typedef void(^SDImageCacheCheckCompletionBlock)(BOOL isInCache); +typedef void(^SDImageCacheCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize); +typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * _Nonnull key); typedef void(^SDImageCacheQueryCompletionBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType); typedef void(^SDImageCacheContainsCompletionBlock)(SDImageCacheType containsCacheType); @@ -54,7 +57,7 @@ FOUNDATION_EXPORT UIImage * _Nullable SDWebImageCacheDecodeImageData(NSData * _N Though the best practice to custom image cache, is to write your own class which conform `SDMemoryCache` or `SDDiskCache` protocol for `SDImageCache` class (See more on `SDImageCacheConfig.memoryCacheClass & SDImageCacheConfig.diskCacheClass`). However, if your own cache implementation contains more advanced feature beyond `SDImageCache` itself, you can consider to provide this instead. For example, you can even use a cache manager like `SDWebImageCachesManager` to register multiple caches. */ -@protocol SDWebImageCache +@protocol SDImageCache @required /** diff --git a/SDWebImage/SDWebImageCache.m b/SDWebImage/SDImageCacheDefine.m similarity index 98% rename from SDWebImage/SDWebImageCache.m rename to SDWebImage/SDImageCacheDefine.m index bfd67063..d29edc9f 100644 --- a/SDWebImage/SDWebImageCache.m +++ b/SDWebImage/SDImageCacheDefine.m @@ -6,7 +6,7 @@ * file that was distributed with this source code. */ -#import "SDWebImageCache.h" +#import "SDImageCacheDefine.h" #import "SDWebImageCodersManager.h" #import "SDWebImageCoderHelper.h" #import "SDAnimatedImage.h" diff --git a/SDWebImage/SDImageCachesManager.h b/SDWebImage/SDImageCachesManager.h index f6aabb62..08eece9a 100644 --- a/SDWebImage/SDImageCachesManager.h +++ b/SDWebImage/SDImageCachesManager.h @@ -7,7 +7,7 @@ */ #import -#import "SDWebImageCache.h" +#import "SDImageCacheDefine.h" typedef NS_ENUM(NSUInteger, SDImageCachesManagerOperationPolicy) { SDImageCachesManagerOperationPolicySerial, // process all caches serially (from the highest priority to the lowest priority cache by order) @@ -16,7 +16,7 @@ typedef NS_ENUM(NSUInteger, SDImageCachesManagerOperationPolicy) { SDImageCachesManagerOperationPolicyLowestOnly // process the lowest priority cache only }; -@interface SDImageCachesManager : NSObject +@interface SDImageCachesManager : NSObject /** Returns the global shared caches manager instance. @@ -58,20 +58,20 @@ typedef NS_ENUM(NSUInteger, SDImageCachesManagerOperationPolicy) { /** All caches in caches manager. The caches array is a priority queue, which means the later added cache will have the highest priority */ -@property (atomic, copy, readwrite, nullable) NSArray> *caches; +@property (atomic, copy, readwrite, nullable) NSArray> *caches; /** Add a new cache to the end of caches array. Which has the highest priority. @param cache cache */ -- (void)addCache:(nonnull id)cache; +- (void)addCache:(nonnull id)cache; /** Remove a cache in the caches array. @param cache cache */ -- (void)removeCache:(nonnull id)cache; +- (void)removeCache:(nonnull id)cache; @end diff --git a/SDWebImage/SDImageCachesManager.m b/SDWebImage/SDImageCachesManager.m index 2b26f229..111f806c 100644 --- a/SDWebImage/SDImageCachesManager.m +++ b/SDWebImage/SDImageCachesManager.m @@ -95,11 +95,11 @@ #pragma mark - Cache IO operations -- (void)addCache:(id)cache { - if (![cache conformsToProtocol:@protocol(SDWebImageCache)]) { +- (void)addCache:(id)cache { + if (![cache conformsToProtocol:@protocol(SDImageCache)]) { return; } - NSMutableArray> *mutableCaches = [self.caches mutableCopy]; + NSMutableArray> *mutableCaches = [self.caches mutableCopy]; if (!mutableCaches) { mutableCaches = [NSMutableArray array]; } @@ -107,11 +107,11 @@ self.caches = [mutableCaches copy]; } -- (void)removeCache:(id)cache { - if (![cache conformsToProtocol:@protocol(SDWebImageCache)]) { +- (void)removeCache:(id)cache { + if (![cache conformsToProtocol:@protocol(SDImageCache)]) { return; } - NSMutableArray> *mutableCaches = [self.caches mutableCopy]; + NSMutableArray> *mutableCaches = [self.caches mutableCopy]; [mutableCaches removeObject:cache]; self.caches = [mutableCaches copy]; } @@ -122,7 +122,7 @@ if (!key) { return nil; } - NSArray> *caches = [self.caches copy]; + NSArray> *caches = [self.caches copy]; NSUInteger count = caches.count; if (count == 0) { return nil; @@ -131,12 +131,12 @@ } switch (self.queryOperationPolicy) { case SDImageCachesManagerOperationPolicyHighestOnly: { - id cache = caches.lastObject; + id cache = caches.lastObject; return [cache queryImageForKey:key options:options context:context completion:completionBlock]; } break; case SDImageCachesManagerOperationPolicyLowestOnly: { - id cache = caches.firstObject; + id cache = caches.firstObject; return [cache queryImageForKey:key options:options context:context completion:completionBlock]; } break; @@ -164,7 +164,7 @@ if (!key) { return; } - NSArray> *caches = [self.caches copy]; + NSArray> *caches = [self.caches copy]; NSUInteger count = caches.count; if (count == 0) { return; @@ -174,12 +174,12 @@ } switch (self.storeOperationPolicy) { case SDImageCachesManagerOperationPolicyHighestOnly: { - id cache = caches.lastObject; + id cache = caches.lastObject; [cache storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock]; } break; case SDImageCachesManagerOperationPolicyLowestOnly: { - id cache = caches.firstObject; + id cache = caches.firstObject; [cache storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock]; } break; @@ -202,7 +202,7 @@ if (!key) { return; } - NSArray> *caches = [self.caches copy]; + NSArray> *caches = [self.caches copy]; NSUInteger count = caches.count; if (count == 0) { return; @@ -212,12 +212,12 @@ } switch (self.removeOperationPolicy) { case SDImageCachesManagerOperationPolicyHighestOnly: { - id cache = caches.lastObject; + id cache = caches.lastObject; [cache removeImageForKey:key cacheType:cacheType completion:completionBlock]; } break; case SDImageCachesManagerOperationPolicyLowestOnly: { - id cache = caches.firstObject; + id cache = caches.firstObject; [cache removeImageForKey:key cacheType:cacheType completion:completionBlock]; } break; @@ -240,7 +240,7 @@ if (!key) { return; } - NSArray> *caches = [self.caches copy]; + NSArray> *caches = [self.caches copy]; NSUInteger count = caches.count; if (count == 0) { return; @@ -250,12 +250,12 @@ } switch (self.clearOperationPolicy) { case SDImageCachesManagerOperationPolicyHighestOnly: { - id cache = caches.lastObject; + id cache = caches.lastObject; [cache containsImageForKey:key cacheType:cacheType completion:completionBlock]; } break; case SDImageCachesManagerOperationPolicyLowestOnly: { - id cache = caches.firstObject; + id cache = caches.firstObject; [cache containsImageForKey:key cacheType:cacheType completion:completionBlock]; } break; @@ -277,7 +277,7 @@ } - (void)clearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock { - NSArray> *caches = [self.caches copy]; + NSArray> *caches = [self.caches copy]; NSUInteger count = caches.count; if (count == 0) { return; @@ -287,12 +287,12 @@ } switch (self.clearOperationPolicy) { case SDImageCachesManagerOperationPolicyHighestOnly: { - id cache = caches.lastObject; + id cache = caches.lastObject; [cache clearWithCacheType:cacheType completion:completionBlock]; } break; case SDImageCachesManagerOperationPolicyLowestOnly: { - id cache = caches.firstObject; + id cache = caches.firstObject; [cache clearWithCacheType:cacheType completion:completionBlock]; } break; @@ -313,10 +313,10 @@ #pragma mark - Concurrent Operation -- (void)concurrentQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { +- (void)concurrentQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); - for (id cache in enumerator) { + for (id cache in enumerator) { [cache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { if (operation.isCancelled) { // Cancelled @@ -346,10 +346,10 @@ } } -- (void)concurrentStoreImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { +- (void)concurrentStoreImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); - for (id cache in enumerator) { + for (id cache in enumerator) { [cache storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:^{ if (operation.isCancelled) { // Cancelled @@ -371,10 +371,10 @@ } } -- (void)concurrentRemoveImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { +- (void)concurrentRemoveImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); - for (id cache in enumerator) { + for (id cache in enumerator) { [cache removeImageForKey:key cacheType:cacheType completion:^{ if (operation.isCancelled) { // Cancelled @@ -396,10 +396,10 @@ } } -- (void)concurrentContainsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheContainsCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { +- (void)concurrentContainsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheContainsCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); - for (id cache in enumerator) { + for (id cache in enumerator) { [cache containsImageForKey:key cacheType:cacheType completion:^(SDImageCacheType containsCacheType) { if (operation.isCancelled) { // Cancelled @@ -429,10 +429,10 @@ } } -- (void)concurrentClearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { +- (void)concurrentClearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); - for (id cache in enumerator) { + for (id cache in enumerator) { [cache clearWithCacheType:cacheType completion:^{ if (operation.isCancelled) { // Cancelled @@ -456,10 +456,10 @@ #pragma mark - Serial Operation -- (void)serialQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { +- (void)serialQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); - id cache = enumerator.nextObject; + id cache = enumerator.nextObject; if (!cache) { // Complete [operation done]; @@ -492,9 +492,9 @@ }]; } -- (void)serialStoreImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator { +- (void)serialStoreImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator { NSParameterAssert(enumerator); - id cache = enumerator.nextObject; + id cache = enumerator.nextObject; if (!cache) { // Complete if (completionBlock) { @@ -509,9 +509,9 @@ }]; } -- (void)serialRemoveImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator { +- (void)serialRemoveImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator { NSParameterAssert(enumerator); - id cache = enumerator.nextObject; + id cache = enumerator.nextObject; if (!cache) { // Complete if (completionBlock) { @@ -526,10 +526,10 @@ }]; } -- (void)serialContainsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheContainsCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { +- (void)serialContainsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheContainsCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); - id cache = enumerator.nextObject; + id cache = enumerator.nextObject; if (!cache) { // Complete [operation done]; @@ -562,9 +562,9 @@ }]; } -- (void)serialClearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator { +- (void)serialClearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator> *)enumerator { NSParameterAssert(enumerator); - id cache = enumerator.nextObject; + id cache = enumerator.nextObject; if (!cache) { // Complete if (completionBlock) { diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 6f338d95..83c5fdd6 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -8,7 +8,7 @@ #import "SDWebImageCompat.h" #import "SDWebImageOperation.h" -#import "SDWebImageCache.h" +#import "SDImageCacheDefine.h" #import "SDWebImageDownloader.h" #import "SDWebImageTransformer.h" #import "SDWebImageCacheKeyFilter.h" @@ -99,7 +99,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; /** * The image cache used by manager to query image cache. */ -@property (strong, nonatomic, readonly, nonnull) id imageCache; +@property (strong, nonatomic, readonly, nonnull) id imageCache; /** * The image downloader used by manager to download image. @@ -158,7 +158,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; The default image cache when the manager which is created with no arguments. Such as shared manager or init. Defaults to nil. Means using `SDImageCache.sharedImageCache` */ -@property (nonatomic, class, nullable) id defaultImageCache; +@property (nonatomic, class, nullable) id defaultImageCache; /** The default image downloader for manager which is created with no arguments. Such as shared manager or init. @@ -175,7 +175,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; * Allows to specify instance of cache and image downloader used with image manager. * @return new instance of `SDWebImageManager` with specified cache and downloader. */ -- (nonnull instancetype)initWithCache:(nonnull id)cache downloader:(nonnull SDWebImageDownloader *)downloader NS_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithCache:(nonnull id)cache downloader:(nonnull SDWebImageDownloader *)downloader NS_DESIGNATED_INITIALIZER; /** * Downloads the image at the given URL if not present in cache or return the cached version otherwise. diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 84c72340..b7b91bc9 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -13,7 +13,7 @@ #import "SDAnimatedImage.h" #import "SDWebImageError.h" -static id _defaultImageCache; +static id _defaultImageCache; static SDWebImageDownloader *_defaultImageDownloader; @interface SDWebImageCombinedOperation () @@ -36,12 +36,12 @@ static SDWebImageDownloader *_defaultImageDownloader; @implementation SDWebImageManager -+ (id)defaultImageCache { ++ (id)defaultImageCache { return _defaultImageCache; } -+ (void)setDefaultImageCache:(id)defaultImageCache { - if (defaultImageCache && ![defaultImageCache conformsToProtocol:@protocol(SDWebImageCache)]) { ++ (void)setDefaultImageCache:(id)defaultImageCache { + if (defaultImageCache && ![defaultImageCache conformsToProtocol:@protocol(SDImageCache)]) { return; } _defaultImageCache = defaultImageCache; @@ -68,7 +68,7 @@ static SDWebImageDownloader *_defaultImageDownloader; } - (nonnull instancetype)init { - id cache = [[self class] defaultImageCache]; + id cache = [[self class] defaultImageCache]; if (!cache) { cache = [SDImageCache sharedImageCache]; } @@ -79,7 +79,7 @@ static SDWebImageDownloader *_defaultImageDownloader; return [self initWithCache:cache downloader:downloader]; } -- (nonnull instancetype)initWithCache:(nonnull id)cache downloader:(nonnull SDWebImageDownloader *)downloader { +- (nonnull instancetype)initWithCache:(nonnull id)cache downloader:(nonnull SDWebImageDownloader *)downloader { if ((self = [super init])) { _imageCache = cache; _imageDownloader = downloader; From a6bdba724e0ab0a8445aa23164845a6f1db054f1 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 18 Apr 2018 19:23:45 +0800 Subject: [PATCH 146/361] Fix all cache test --- SDWebImage/SDImageCache.h | 4 +- SDWebImage/SDImageCache.m | 10 ++-- SDWebImage/SDImageCacheDefine.h | 4 +- SDWebImage/SDImageCacheDefine.m | 2 +- SDWebImage/SDImageCachesManager.m | 2 +- Tests/Tests/SDImageCacheTests.m | 94 +++++++++++++++---------------- WebImage/SDWebImage.h | 4 +- 7 files changed, 60 insertions(+), 60 deletions(-) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index e70c280f..b4bfeaf2 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -324,8 +324,8 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { @end /** - * SDImageCache is the built-in image cache implementation for web image manager. It adopts `SDWebImageCache` protocol to provide the function for web image manager to use for image loading process. + * SDImageCache is the built-in image cache implementation for web image manager. It adopts `SDImageCache` protocol to provide the function for web image manager to use for image loading process. */ -@interface SDImageCache (SDWebImageCache) +@interface SDImageCache (SDImageCache) @end diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index dd92e8e4..dbcc31f0 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -59,10 +59,10 @@ diskCacheDirectory:(nonnull NSString *)directory config:(nullable SDImageCacheConfig *)config { if ((self = [super init])) { - NSString *fullNamespace = [@"com.hackemist.SDWebImageCache." stringByAppendingString:ns]; + NSString *fullNamespace = [@"com.hackemist.SDImageCache." stringByAppendingString:ns]; // Create IO serial queue - _ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL); + _ioQueue = dispatch_queue_create("com.hackemist.SDImageCache", DISPATCH_QUEUE_SERIAL); if (!config) { config = SDImageCacheConfig.defaultCacheConfig; @@ -317,7 +317,7 @@ - (nullable UIImage *)diskImageForKey:(nullable NSString *)key data:(nullable NSData *)data options:(SDImageCacheOptions)options context:(SDWebImageContext *)context { if (data) { - UIImage *image = SDWebImageCacheDecodeImageData(data, key, [[self class] imageOptionsFromCacheOptions:options], context); + UIImage *image = SDImageCacheDecodeImageData(data, key, [[self class] imageOptionsFromCacheOptions:options], context); return image; } else { return nil; @@ -568,9 +568,9 @@ @end -@implementation SDImageCache (SDWebImageCache) +@implementation SDImageCache (SDImageCache) -#pragma mark - SDWebImageCache +#pragma mark - SDImageCache - (id)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock { SDImageCacheOptions cacheOptions = 0; diff --git a/SDWebImage/SDImageCacheDefine.h b/SDWebImage/SDImageCacheDefine.h index caf186ed..8b09e963 100644 --- a/SDWebImage/SDImageCacheDefine.h +++ b/SDWebImage/SDImageCacheDefine.h @@ -50,12 +50,12 @@ typedef void(^SDImageCacheContainsCompletionBlock)(SDImageCacheType containsCach @param context The context arg from the input @return The decoded image for current image data query from cache */ -FOUNDATION_EXPORT UIImage * _Nullable SDWebImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context); +FOUNDATION_EXPORT UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context); /** This is the image cache protocol to provide custom image cache for `SDWebImageManager`. Though the best practice to custom image cache, is to write your own class which conform `SDMemoryCache` or `SDDiskCache` protocol for `SDImageCache` class (See more on `SDImageCacheConfig.memoryCacheClass & SDImageCacheConfig.diskCacheClass`). - However, if your own cache implementation contains more advanced feature beyond `SDImageCache` itself, you can consider to provide this instead. For example, you can even use a cache manager like `SDWebImageCachesManager` to register multiple caches. + However, if your own cache implementation contains more advanced feature beyond `SDImageCache` itself, you can consider to provide this instead. For example, you can even use a cache manager like `SDImageCachesManager` to register multiple caches. */ @protocol SDImageCache diff --git a/SDWebImage/SDImageCacheDefine.m b/SDWebImage/SDImageCacheDefine.m index d29edc9f..c0bfab4e 100644 --- a/SDWebImage/SDImageCacheDefine.m +++ b/SDWebImage/SDImageCacheDefine.m @@ -12,7 +12,7 @@ #import "SDAnimatedImage.h" #import "UIImage+WebCache.h" -UIImage * _Nullable SDWebImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context) { +UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context) { UIImage *image; BOOL decodeFirstFrame = options & SDWebImageDecodeFirstFrameOnly; NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor]; diff --git a/SDWebImage/SDImageCachesManager.m b/SDWebImage/SDImageCachesManager.m index 111f806c..1da509f0 100644 --- a/SDWebImage/SDImageCachesManager.m +++ b/SDWebImage/SDImageCachesManager.m @@ -116,7 +116,7 @@ self.caches = [mutableCaches copy]; } -#pragma mark - SDWebImageCache +#pragma mark - SDImageCache - (id)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock { if (!key) { diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index e8050382..bc9f3623 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -9,7 +9,7 @@ #import "SDTestCase.h" #import #import -#import +#import #import "SDWebImageTestDecoder.h" #import "SDMockFileManager.h" #import "SDWebImageTestCache.h" @@ -30,11 +30,11 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; @implementation SDImageCacheTests + (void)setUp { - [[SDWebImageCachesManager sharedManager] addCache:[SDImageCache sharedImageCache]]; + [[SDImageCachesManager sharedManager] addCache:[SDImageCache sharedImageCache]]; } + (void)tearDown { - [[SDWebImageCachesManager sharedManager] removeCache:[SDImageCache sharedImageCache]]; + [[SDImageCachesManager sharedManager] removeCache:[SDImageCache sharedImageCache]]; } - (void)test01SharedImageCache { @@ -362,20 +362,20 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; expect([diskCache isKindOfClass:[SDWebImageTestDiskCache class]]).to.beTruthy(); } -#pragma mark - SDWebImageCache & SDWebImageCachesManager -- (void)test50SDWebImageCacheQueryOp { - XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache query op works"]; +#pragma mark - SDImageCache & SDImageCachesManager +- (void)test50SDImageCacheQueryOp { + XCTestExpectation *expectation = [self expectationWithDescription:@"SDImageCache query op works"]; [[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG toDisk:NO completion:nil]; - [[SDWebImageCachesManager sharedManager] queryImageForKey:kTestImageKeyJPEG options:0 context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { + [[SDImageCachesManager sharedManager] queryImageForKey:kTestImageKeyJPEG options:0 context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { expect(image).notTo.beNil(); [expectation fulfill]; }]; [self waitForExpectationsWithCommonTimeout]; } -- (void)test51SDWebImageCacheStoreOp { - XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache store op works"]; - [[SDWebImageCachesManager sharedManager] storeImage:[self testJPEGImage] imageData:nil forKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeAll completion:^{ +- (void)test51SDImageCacheStoreOp { + XCTestExpectation *expectation = [self expectationWithDescription:@"SDImageCache store op works"]; + [[SDImageCachesManager sharedManager] storeImage:[self testJPEGImage] imageData:nil forKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeAll completion:^{ UIImage *image = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]; expect(image).notTo.beNil(); [[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) { @@ -386,9 +386,9 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; [self waitForExpectationsWithCommonTimeout]; } -- (void)test52SDWebImageCacheRemoveOp { - XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache remove op works"]; - [[SDWebImageCachesManager sharedManager] removeImageForKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeDisk completion:^{ +- (void)test52SDImageCacheRemoveOp { + XCTestExpectation *expectation = [self expectationWithDescription:@"SDImageCache remove op works"]; + [[SDImageCachesManager sharedManager] removeImageForKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeDisk completion:^{ UIImage *memoryImage = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]; expect(memoryImage).notTo.beNil(); [[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) { @@ -399,18 +399,18 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; [self waitForExpectationsWithCommonTimeout]; } -- (void)test53SDWebImageCacheContainsOp { - XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache contains op works"]; - [[SDWebImageCachesManager sharedManager] containsImageForKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeAll completion:^(SDImageCacheType containsCacheType) { +- (void)test53SDImageCacheContainsOp { + XCTestExpectation *expectation = [self expectationWithDescription:@"SDImageCache contains op works"]; + [[SDImageCachesManager sharedManager] containsImageForKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeAll completion:^(SDImageCacheType containsCacheType) { expect(containsCacheType).equal(SDImageCacheTypeMemory); [expectation fulfill]; }]; [self waitForExpectationsWithCommonTimeout]; } -- (void)test54SDWebImageCacheClearOp { - XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache clear op works"]; - [[SDWebImageCachesManager sharedManager] clearWithCacheType:SDImageCacheTypeAll completion:^{ +- (void)test54SDImageCacheClearOp { + XCTestExpectation *expectation = [self expectationWithDescription:@"SDImageCache clear op works"]; + [[SDImageCachesManager sharedManager] clearWithCacheType:SDImageCacheTypeAll completion:^{ UIImage *memoryImage = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]; expect(memoryImage).to.beNil(); [[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) { @@ -421,8 +421,8 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; [self waitForExpectationsWithCommonTimeout]; } -- (void)test55SDWebImageCachesManagerOperationPolicySimple { - SDWebImageCachesManager *cachesManager = [[SDWebImageCachesManager alloc] init]; +- (void)test55SDImageCachesManagerOperationPolicySimple { + SDImageCachesManager *cachesManager = [[SDImageCachesManager alloc] init]; SDImageCache *cache1 = [[SDImageCache alloc] initWithNamespace:@"cache1"]; SDImageCache *cache2 = [[SDImageCache alloc] initWithNamespace:@"cache2"]; [cachesManager addCache:cache1]; @@ -432,11 +432,11 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; [[NSFileManager defaultManager] removeItemAtPath:cache2.diskCachePath error:nil]; // LowestOnly - cachesManager.queryOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly; - cachesManager.storeOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly; - cachesManager.removeOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly; - cachesManager.containsOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly; - cachesManager.clearOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly; + cachesManager.queryOperationPolicy = SDImageCachesManagerOperationPolicyLowestOnly; + cachesManager.storeOperationPolicy = SDImageCachesManagerOperationPolicyLowestOnly; + cachesManager.removeOperationPolicy = SDImageCachesManagerOperationPolicyLowestOnly; + cachesManager.containsOperationPolicy = SDImageCachesManagerOperationPolicyLowestOnly; + cachesManager.clearOperationPolicy = SDImageCachesManagerOperationPolicyLowestOnly; [cachesManager queryImageForKey:kTestImageKeyJPEG options:0 context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { expect(image).to.beNil(); }]; @@ -451,11 +451,11 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; [cachesManager clearWithCacheType:SDImageCacheTypeMemory completion:nil]; // HighestOnly - cachesManager.queryOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly; - cachesManager.storeOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly; - cachesManager.removeOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly; - cachesManager.containsOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly; - cachesManager.clearOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly; + cachesManager.queryOperationPolicy = SDImageCachesManagerOperationPolicyHighestOnly; + cachesManager.storeOperationPolicy = SDImageCachesManagerOperationPolicyHighestOnly; + cachesManager.removeOperationPolicy = SDImageCachesManagerOperationPolicyHighestOnly; + cachesManager.containsOperationPolicy = SDImageCachesManagerOperationPolicyHighestOnly; + cachesManager.clearOperationPolicy = SDImageCachesManagerOperationPolicyHighestOnly; [cachesManager queryImageForKey:kTestImageKeyPNG options:0 context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { expect(image).to.beNil(); }]; @@ -470,9 +470,9 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; [cachesManager clearWithCacheType:SDImageCacheTypeMemory completion:nil]; } -- (void)test56SDWebImageCachesManagerOperationPolicyConcurrent { - XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCachesManager operation cocurrent policy works"]; - SDWebImageCachesManager *cachesManager = [[SDWebImageCachesManager alloc] init]; +- (void)test56SDImageCachesManagerOperationPolicyConcurrent { + XCTestExpectation *expectation = [self expectationWithDescription:@"SDImageCachesManager operation cocurrent policy works"]; + SDImageCachesManager *cachesManager = [[SDImageCachesManager alloc] init]; SDImageCache *cache1 = [[SDImageCache alloc] initWithNamespace:@"cache1"]; SDImageCache *cache2 = [[SDImageCache alloc] initWithNamespace:@"cache2"]; [cachesManager addCache:cache1]; @@ -485,11 +485,11 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; // Cocurrent // Check all concurrent op - cachesManager.queryOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent; - cachesManager.storeOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent; - cachesManager.removeOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent; - cachesManager.containsOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent; - cachesManager.clearOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent; + cachesManager.queryOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; + cachesManager.storeOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; + cachesManager.removeOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; + cachesManager.containsOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; + cachesManager.clearOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; [cachesManager queryImageForKey:kConcurrentTestImageKey options:0 context:nil completion:nil]; [cachesManager storeImage:[self testJPEGImage] imageData:nil forKey:kConcurrentTestImageKey cacheType:SDImageCacheTypeMemory completion:nil]; [cachesManager removeImageForKey:kConcurrentTestImageKey cacheType:SDImageCacheTypeMemory completion:nil]; @@ -511,9 +511,9 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; [self waitForExpectationsWithCommonTimeout]; } -- (void)test57SDWebImageCachesManagerOperationPolicySerial { - XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCachesManager operation serial policy works"]; - SDWebImageCachesManager *cachesManager = [[SDWebImageCachesManager alloc] init]; +- (void)test57SDImageCachesManagerOperationPolicySerial { + XCTestExpectation *expectation = [self expectationWithDescription:@"SDImageCachesManager operation serial policy works"]; + SDImageCachesManager *cachesManager = [[SDImageCachesManager alloc] init]; SDImageCache *cache1 = [[SDImageCache alloc] initWithNamespace:@"cache1"]; SDImageCache *cache2 = [[SDImageCache alloc] initWithNamespace:@"cache2"]; [cachesManager addCache:cache1]; @@ -526,11 +526,11 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; // Serial // Check all serial op - cachesManager.queryOperationPolicy = SDWebImageCachesManagerOperationPolicySerial; - cachesManager.storeOperationPolicy = SDWebImageCachesManagerOperationPolicySerial; - cachesManager.removeOperationPolicy = SDWebImageCachesManagerOperationPolicySerial; - cachesManager.containsOperationPolicy = SDWebImageCachesManagerOperationPolicySerial; - cachesManager.clearOperationPolicy = SDWebImageCachesManagerOperationPolicySerial; + cachesManager.queryOperationPolicy = SDImageCachesManagerOperationPolicySerial; + cachesManager.storeOperationPolicy = SDImageCachesManagerOperationPolicySerial; + cachesManager.removeOperationPolicy = SDImageCachesManagerOperationPolicySerial; + cachesManager.containsOperationPolicy = SDImageCachesManagerOperationPolicySerial; + cachesManager.clearOperationPolicy = SDImageCachesManagerOperationPolicySerial; [cachesManager queryImageForKey:kSerialTestImageKey options:0 context:nil completion:nil]; [cachesManager storeImage:[self testJPEGImage] imageData:nil forKey:kSerialTestImageKey cacheType:SDImageCacheTypeMemory completion:nil]; [cachesManager removeImageForKey:kSerialTestImageKey cacheType:SDImageCacheTypeMemory completion:nil]; diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index a98f0e97..7207905e 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -28,8 +28,8 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import -#import -#import +#import +#import #import #import #import From 57db312cc5d7424f20fb1ff5b772c9a777704bfd Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sun, 15 Apr 2018 16:40:42 +0800 Subject: [PATCH 147/361] Add `SDWebImageLoader` protocol for custom image loader. Also introduce the `SDWebImageLoadersManager` to manage multiple loaders with priority --- .../SDWebImage Demo/MasterViewController.m | 8 +- SDWebImage.xcodeproj/project.pbxproj | 56 +++++++++ SDWebImage/SDWebImageDownloader.h | 15 ++- SDWebImage/SDWebImageDownloader.m | 49 ++++++++ SDWebImage/SDWebImageLoader.h | 68 +++++++++++ SDWebImage/SDWebImageLoader.m | 9 ++ SDWebImage/SDWebImageLoadersManager.h | 34 ++++++ SDWebImage/SDWebImageLoadersManager.m | 112 ++++++++++++++++++ SDWebImage/SDWebImageManager.h | 5 +- SDWebImage/SDWebImageManager.m | 32 +---- WebImage/SDWebImage.h | 2 + 11 files changed, 352 insertions(+), 38 deletions(-) create mode 100644 SDWebImage/SDWebImageLoader.h create mode 100644 SDWebImage/SDWebImageLoader.m create mode 100644 SDWebImage/SDWebImageLoadersManager.h create mode 100644 SDWebImage/SDWebImageLoadersManager.m diff --git a/Examples/SDWebImage Demo/MasterViewController.m b/Examples/SDWebImage Demo/MasterViewController.m index 8ead3031..45e60953 100644 --- a/Examples/SDWebImage Demo/MasterViewController.m +++ b/Examples/SDWebImage Demo/MasterViewController.m @@ -56,8 +56,10 @@ // HTTP NTLM auth example // Add your NTLM image url to the array below and replace the credentials - [SDWebImageManager sharedManager].imageDownloader.config.username = @"httpwatch"; - [SDWebImageManager sharedManager].imageDownloader.config.password = @"httpwatch01"; + [SDWebImageDownloader sharedDownloader].config.username = @"httpwatch"; + [SDWebImageDownloader sharedDownloader].config.password = @"httpwatch01"; + [[SDWebImageDownloader sharedDownloader] setValue:@"SDWebImage Demo" forHTTPHeaderField:@"AppName"]; + [SDWebImageDownloader sharedDownloader].config.executionOrder = SDWebImageDownloaderLIFOExecutionOrder; self.objects = [NSMutableArray arrayWithObjects: @"http://www.httpwatch.com/httpgallery/authentication/authenticatedimage/default.aspx?0.35786508303135633", // requires HTTP auth, used to demo the NTLM auth @@ -78,8 +80,6 @@ } } - [SDWebImageManager.sharedManager.imageDownloader setValue:@"SDWebImage Demo" forHTTPHeaderField:@"AppName"]; - SDWebImageManager.sharedManager.imageDownloader.config.executionOrder = SDWebImageDownloaderLIFOExecutionOrder; return self; } diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 11e46035..9b09d6f3 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -51,6 +51,30 @@ 320CAE1E2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; 320CAE1F2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; 320CAE202086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; + 321B37812083290E00C0EA77 /* SDWebImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37822083290E00C0EA77 /* SDWebImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37832083290E00C0EA77 /* SDWebImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37842083290E00C0EA77 /* SDWebImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37852083290E00C0EA77 /* SDWebImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37862083290E00C0EA77 /* SDWebImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37872083290E00C0EA77 /* SDWebImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */; }; + 321B37882083290E00C0EA77 /* SDWebImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */; }; + 321B37892083290E00C0EA77 /* SDWebImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */; }; + 321B378A2083290E00C0EA77 /* SDWebImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */; }; + 321B378B2083290E00C0EA77 /* SDWebImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */; }; + 321B378C2083290E00C0EA77 /* SDWebImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */; }; + 321B378D2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B378E2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B378F2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37902083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37912083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37922083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37932083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */; }; + 321B37942083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */; }; + 321B37952083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */; }; + 321B37962083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */; }; + 321B37972083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */; }; + 321B37982083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */; }; 321DB3612011D4D70015D2CB /* NSButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321DB3622011D4D70015D2CB /* NSButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */; }; 321E60861F38E8C800405457 /* SDWebImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDWebImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1519,6 +1543,10 @@ 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImageRep.m; sourceTree = ""; }; 320CAE132086F50500CFFC80 /* SDWebImageError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageError.h; sourceTree = ""; }; 320CAE142086F50500CFFC80 /* SDWebImageError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageError.m; sourceTree = ""; }; + 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageLoader.h; sourceTree = ""; }; + 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageLoader.m; sourceTree = ""; }; + 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageLoadersManager.h; sourceTree = ""; }; + 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageLoadersManager.m; sourceTree = ""; }; 321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSButton+WebCache.h"; path = "SDWebImage/NSButton+WebCache.h"; sourceTree = ""; }; 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSButton+WebCache.m"; path = "SDWebImage/NSButton+WebCache.m"; sourceTree = ""; }; 321E60841F38E8C800405457 /* SDWebImageCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoder.h; sourceTree = ""; }; @@ -2137,6 +2165,10 @@ 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */, 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */, 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */, + 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */, + 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */, + 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */, + 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */, ); name = Downloader; sourceTree = ""; @@ -2346,6 +2378,7 @@ 32B9B53A206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AD2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 80377C4A1F2F666300F89830 /* bit_writer_utils.h in Headers */, + 321B37902083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, 4397D2F81D0DF44200BB2784 /* MKAnnotationView+WebCache.h in Headers */, 323F8BE71F38EF770092B609 /* vp8li_enc.h in Headers */, 329A185C1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, @@ -2389,6 +2422,7 @@ 328BB6D02082581100760D6C /* SDMemoryCache.h in Headers */, 321E60891F38E8C800405457 /* SDWebImageCoder.h in Headers */, 00733A721BC4880E00A5A117 /* UIView+WebCacheOperation.h in Headers */, + 321B37842083290E00C0EA77 /* SDWebImageLoader.h in Headers */, 80377C481F2F666300F89830 /* bit_reader_utils.h in Headers */, 80377C511F2F666300F89830 /* huffman_encode_utils.h in Headers */, 32484778201775F600AF9E5A /* SDAnimatedImage.h in Headers */, @@ -2466,6 +2500,7 @@ 4314D16F1D0E0E3B004B36C9 /* NSData+ImageContentType.h in Headers */, 80377C121F2F666300F89830 /* bit_reader_inl_utils.h in Headers */, 4314D1701D0E0E3B004B36C9 /* mux.h in Headers */, + 321B378E2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, 321E60871F38E8C800405457 /* SDWebImageCoder.h in Headers */, 80377EA21F2F66D400F89830 /* vp8i_dec.h in Headers */, 320CAE162086F50500CFFC80 /* SDWebImageError.h in Headers */, @@ -2474,6 +2509,7 @@ 80377C211F2F666300F89830 /* quant_levels_dec_utils.h in Headers */, 4314D1721D0E0E3B004B36C9 /* SDWebImageCompat.h in Headers */, 32484776201775F600AF9E5A /* SDAnimatedImage.h in Headers */, + 321B37822083290E00C0EA77 /* SDWebImageLoader.h in Headers */, 80377C251F2F666300F89830 /* random_utils.h in Headers */, 80377D4F1F2F66A700F89830 /* lossless.h in Headers */, 80377D511F2F66A700F89830 /* msa_macro.h in Headers */, @@ -2528,6 +2564,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 321B37912083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, 80377C791F2F666400F89830 /* utils.h in Headers */, 328BB6A02081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, 323F8B721F38EF770092B609 /* delta_palettization_enc.h in Headers */, @@ -2540,6 +2577,7 @@ 321E608A1F38E8C800405457 /* SDWebImageCoder.h in Headers */, 32484767201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80377C601F2F666400F89830 /* bit_reader_inl_utils.h in Headers */, + 321B37852083290E00C0EA77 /* SDWebImageLoader.h in Headers */, 329A185D1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 431BB6DC1D06D2C1006A3455 /* UIButton+WebCache.h in Headers */, 431BB6E11D06D2C1006A3455 /* SDWebImage.h in Headers */, @@ -2634,6 +2672,7 @@ 32B9B53C206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AF2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 4397D2BA1D0DDD8C00BB2784 /* demux.h in Headers */, + 321B37922083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, 80377C8F1F2F666400F89830 /* rescaler_utils.h in Headers */, 4397D2BD1D0DDD8C00BB2784 /* types.h in Headers */, 4397D2C01D0DDD8C00BB2784 /* SDWebImage.h in Headers */, @@ -2677,6 +2716,7 @@ 328BB6D22082581100760D6C /* SDMemoryCache.h in Headers */, 323F8BDD1F38EF770092B609 /* vp8i_enc.h in Headers */, 323F8B671F38EF770092B609 /* cost_enc.h in Headers */, + 321B37862083290E00C0EA77 /* SDWebImageLoader.h in Headers */, 80377EE11F2F66D500F89830 /* vp8_dec.h in Headers */, 80377EE41F2F66D500F89830 /* vp8li_dec.h in Headers */, 80377C931F2F666400F89830 /* utils.h in Headers */, @@ -2733,6 +2773,7 @@ 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AC2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 80377C301F2F666300F89830 /* bit_writer_utils.h in Headers */, + 321B378F2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, 431739541CDFC8B70008FEB9 /* types.h in Headers */, 323F8BE61F38EF770092B609 /* vp8li_enc.h in Headers */, 329A185B1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, @@ -2776,6 +2817,7 @@ 328BB6CF2082581100760D6C /* SDMemoryCache.h in Headers */, 321E60881F38E8C800405457 /* SDWebImageCoder.h in Headers */, 4A2CAE371AB4BB7500B6BC39 /* UIView+WebCacheOperation.h in Headers */, + 321B37832083290E00C0EA77 /* SDWebImageLoader.h in Headers */, 80377C2E1F2F666300F89830 /* bit_reader_utils.h in Headers */, 80377C371F2F666300F89830 /* huffman_encode_utils.h in Headers */, 32484777201775F600AF9E5A /* SDAnimatedImage.h in Headers */, @@ -2868,6 +2910,7 @@ 321E60BE1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 5376131E155AD0D5005750A4 /* SDWebImagePrefetcher.h in Headers */, 32F7C06F2030114C00873181 /* SDWebImageTransformer.h in Headers */, + 321B378D2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, 324DF4B4200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 80377CE11F2F66A100F89830 /* common_sse2.h in Headers */, 80377C0B1F2F665300F89830 /* random_utils.h in Headers */, @@ -2892,6 +2935,7 @@ 323F8BE41F38EF770092B609 /* vp8li_enc.h in Headers */, 320CAE152086F50500CFFC80 /* SDWebImageError.h in Headers */, 323F8B861F38EF770092B609 /* histogram_enc.h in Headers */, + 321B37812083290E00C0EA77 /* SDWebImageLoader.h in Headers */, 323F8BF61F38EF770092B609 /* animi.h in Headers */, 321E60861F38E8C800405457 /* SDWebImageCoder.h in Headers */, 321E60B01F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, @@ -3193,6 +3237,7 @@ 80377DD71F2F66A700F89830 /* lossless_sse2.c in Sources */, 80377DA81F2F66A700F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, 80377DB11F2F66A700F89830 /* cost_mips_dsp_r2.c in Sources */, + 321B37962083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */, 80377C581F2F666300F89830 /* random_utils.c in Sources */, 323F8B591F38EF770092B609 /* config_enc.c in Sources */, 80377DE91F2F66A700F89830 /* yuv_mips32.c in Sources */, @@ -3252,6 +3297,7 @@ 80377C561F2F666300F89830 /* quant_levels_utils.c in Sources */, 323F8BCF1F38EF770092B609 /* token_enc.c in Sources */, 80377DD11F2F66A700F89830 /* lossless_enc_sse2.c in Sources */, + 321B378A2083290E00C0EA77 /* SDWebImageLoader.m in Sources */, 32484772201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 323F8C1D1F38EF770092B609 /* muxread.c in Sources */, 807A12311F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */, @@ -3395,6 +3441,7 @@ 80377E9C1F2F66D400F89830 /* idec_dec.c in Sources */, 323F8B7B1F38EF770092B609 /* frame_enc.c in Sources */, 80377D211F2F66A700F89830 /* alpha_processing_sse41.c in Sources */, + 321B37942083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */, 323F8B8D1F38EF770092B609 /* iterator_enc.c in Sources */, 3248475E201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 80377D481F2F66A700F89830 /* lossless_enc_sse41.c in Sources */, @@ -3455,6 +3502,7 @@ 80377E991F2F66D400F89830 /* buffer_dec.c in Sources */, 80377C201F2F666300F89830 /* quant_levels_dec_utils.c in Sources */, 32F7C07F2030719600873181 /* UIImage+Transform.m in Sources */, + 321B37882083290E00C0EA77 /* SDWebImageLoader.m in Sources */, 80377D471F2F66A700F89830 /* lossless_enc_sse2.c in Sources */, 80377C1E1F2F666300F89830 /* huffman_utils.c in Sources */, ); @@ -3559,6 +3607,7 @@ 80377DF01F2F66A800F89830 /* alpha_processing_sse41.c in Sources */, 80377ECC1F2F66D500F89830 /* idec_dec.c in Sources */, 323F8B7E1F38EF770092B609 /* frame_enc.c in Sources */, + 321B37972083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */, 80377E171F2F66A800F89830 /* lossless_enc_sse41.c in Sources */, 32484761201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 323F8B901F38EF770092B609 /* iterator_enc.c in Sources */, @@ -3619,6 +3668,7 @@ 80377EC91F2F66D500F89830 /* buffer_dec.c in Sources */, 80377C6C1F2F666400F89830 /* huffman_utils.c in Sources */, 32F7C0822030719600873181 /* UIImage+Transform.m in Sources */, + 321B378B2083290E00C0EA77 /* SDWebImageLoader.m in Sources */, 80377E161F2F66A800F89830 /* lossless_enc_sse2.c in Sources */, 431BB6C71D06D2C1006A3455 /* UIImageView+HighlightedWebCache.m in Sources */, ); @@ -3707,6 +3757,7 @@ 32F21B5C20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 32D122292080B2EB003685A3 /* SDWebImageCache.m in Sources */, 80377E3B1F2F66A800F89830 /* cost_mips_dsp_r2.c in Sources */, + 321B378C2083290E00C0EA77 /* SDWebImageLoader.m in Sources */, 4397D29B1D0DDD8C00BB2784 /* SDWebImageDownloader.m in Sources */, 80377E711F2F66A800F89830 /* upsampling.c in Sources */, 328BB6A72081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, @@ -3784,6 +3835,7 @@ 323F8B851F38EF770092B609 /* histogram_enc.c in Sources */, 80377EE51F2F66D500F89830 /* webp_dec.c in Sources */, 4397D2B01D0DDD8C00BB2784 /* SDImageCache.m in Sources */, + 321B37982083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */, 32F7C07A2030114C00873181 /* SDWebImageTransformer.m in Sources */, 80377E4F1F2F66A800F89830 /* enc_sse41.c in Sources */, 80377E701F2F66A800F89830 /* upsampling_sse2.c in Sources */, @@ -3855,6 +3907,7 @@ 80377D921F2F66A700F89830 /* lossless_sse2.c in Sources */, 80377D631F2F66A700F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, 80377D6C1F2F66A700F89830 /* cost_mips_dsp_r2.c in Sources */, + 321B37952083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */, 4A2CAE361AB4BB7500B6BC39 /* UIImageView+WebCache.m in Sources */, 323F8B581F38EF770092B609 /* config_enc.c in Sources */, 43C892A21D9D6DDD0022038D /* demux.c in Sources */, @@ -3914,6 +3967,7 @@ 4A2CAE191AB4BB6400B6BC39 /* SDWebImageCompat.m in Sources */, 80377DA11F2F66A700F89830 /* upsampling_sse2.c in Sources */, 323F8BCE1F38EF770092B609 /* token_enc.c in Sources */, + 321B37892083290E00C0EA77 /* SDWebImageLoader.m in Sources */, 32484771201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 80377C3C1F2F666300F89830 /* quant_levels_utils.c in Sources */, 323F8C1C1F38EF770092B609 /* muxread.c in Sources */, @@ -4023,6 +4077,7 @@ 80377CD91F2F66A100F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, 80377CE21F2F66A100F89830 /* cost_mips_dsp_r2.c in Sources */, 5376130B155AD0D5005750A4 /* SDWebImageDownloader.m in Sources */, + 321B37932083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */, 323F8B561F38EF770092B609 /* config_enc.c in Sources */, 43C8929B1D9D6DD70022038D /* demux.c in Sources */, 80377D1A1F2F66A100F89830 /* yuv_mips32.c in Sources */, @@ -4082,6 +4137,7 @@ 80377D171F2F66A100F89830 /* upsampling_sse2.c in Sources */, 323F8BCC1F38EF770092B609 /* token_enc.c in Sources */, 80377C081F2F665300F89830 /* quant_levels_utils.c in Sources */, + 321B37872083290E00C0EA77 /* SDWebImageLoader.m in Sources */, 3248476F201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 323F8C1A1F38EF770092B609 /* muxread.c in Sources */, 807A122E1F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */, diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 23bc0d66..37050719 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -12,6 +12,7 @@ #import "SDWebImageOperation.h" #import "SDWebImageDownloaderConfig.h" #import "SDWebImageDownloaderRequestModifier.h" +#import "SDWebImageLoader.h" typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { /** @@ -86,9 +87,8 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStartNotification; FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStopNotification; -typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL); - -typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished); +typedef SDWebImageLoaderProgressBlock SDWebImageDownloaderProgressBlock; +typedef SDWebImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock; /** * A token associated with each download. Can be used to cancel a download @@ -245,3 +245,12 @@ typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage * _Nullable image, NSD - (void)invalidateSessionAndCancel:(BOOL)cancelPendingOperations; @end + + +/** + SDWebImageDownloader is the built-in image downloader conform to `SDWebImageLoader`. Which provide the HTTP/HTTPS/FTP download, or local file URL using NSURLSession. + However, this downloader does also support customization for advanced users. You can specify `operationClass` in download config to custom download operation, See `SDWebImageDownloaderOperation`. + */ +@interface SDWebImageDownloader (SDWebImageLoader) + +@end diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 1c47878d..d17a6b54 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -462,3 +462,52 @@ didReceiveResponse:(NSURLResponse *)response } @end + +@implementation SDWebImageDownloader (SDWebImageLoader) + +- (BOOL)canLoadWithURL:(NSURL *)url { + if (!url) { + return NO; + } + Class operationClass = self.config.operationClass; + if (!operationClass || [operationClass isSubclassOfClass:[SDWebImageDownloaderOperation class]]) { + // Built-in download operation class, checking all supported NSURLProtocol + NSURLRequest *request = [NSURLRequest requestWithURL:url]; + NSArray *protocolClasses = self.sessionConfiguration.protocolClasses; + for (Class protocolClass in protocolClasses) { + if ([protocolClass isSubclassOfClass:[NSURLProtocol class]]) { + BOOL canLoad = [protocolClass canInitWithRequest:request]; + if (canLoad) { + return YES; + } + continue; + } + } + return NO; + } + // Custom download operation class may not dependent on NSURLSession, always pass YES. + return YES; +} + +- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageLoaderProgressBlock)progressBlock completed:(SDWebImageLoaderCompletedBlock)completedBlock context:(SDWebImageContext *)context { + SDWebImageDownloaderOptions downloaderOptions = 0; + if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority; + if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload; + if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache; + if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground; + if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies; + if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates; + if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority; + if (options & SDWebImageScaleDownLargeImages) downloaderOptions |= SDWebImageDownloaderScaleDownLargeImages; + + if (options & SDWebImageRefreshCached) { + // force progressive off if image already cached but forced refreshing + downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload; + // ignore image read from NSURLCache if image if cached but force refreshing + downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse; + } + + return [self downloadImageWithURL:url options:downloaderOptions context:context progress:progressBlock completed:completedBlock]; +} + +@end diff --git a/SDWebImage/SDWebImageLoader.h b/SDWebImage/SDWebImageLoader.h new file mode 100644 index 00000000..6c891b6b --- /dev/null +++ b/SDWebImage/SDWebImageLoader.h @@ -0,0 +1,68 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import "SDWebImageDefine.h" +#import "SDWebImageOperation.h" + +typedef void(^SDWebImageLoaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL); +typedef void(^SDWebImageLoaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished); +typedef void(^SDWebImageLoaderDataCompletedBlock)(NSData * _Nullable data, NSError * _Nullable error, BOOL finished); + +/** + A `SDImageCacheType` value to specify the cache type information from manager. `SDWebImageManager` will firstly query cache, then if cache miss or `SDWebImageRefreshCached` is set, it will start image loader to load the image. + This can be a hint for image loader to load the image from network and refresh the image from remote location if needed. (NSNumber) + */ +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextLoaderCacheType; + +@protocol SDWebImageLoader + +- (BOOL)canLoadWithURL:(nullable NSURL *)url; + +// We provide two ways to allow a image loader to load the image. +// The first one should return the `UIImage` image instance as well as `NSData` image data. This is suitable for the use case such as progressive download from network, or image directlly from Photos framework. +// The second one should return just the `NSData` image data, we will use the common image decoding logic to process the correct image instance, so the image loader itself can concentrate on only data retriving. This is suitable for the use case such as load the data from file. +// Your image loader **MUST** implement at least one of those protocol, or an assert will occur. We will firstlly ask for `loadImageWithURL:options:progress:completed:context:` if you implement it. If this one return nil, we will continue to ask for `loadImageDataWithURL:options:progress:completed:context:` if you implement it. +// @note It's your responsibility to load the image in the desired global queue(to avoid block main queue). We do not dispatch these method call in a global queue but just from the call queue (For `SDWebImageManager`, it typically call from the main queue). + +@optional +/** + Load the image and image data with the given URL and return the image data. You're responsible for producing the image instance. + + @param url The URL represent the image. Note this may not be a HTTP URL + @param options A mask to specify options to use for this request + @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + @param completedBlock A block called when operation has been completed. + @return An operation which allow the user to cancel the current request. + */ +- (nullable id)loadImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageLoaderProgressBlock)progressBlock + completed:(nullable SDWebImageLoaderCompletedBlock)completedBlock; + +/** + Load the image with the given URL and return the image data. We will automatically handler the image decoding stuff for you. + + @param url The URL represent the image. Note this may not be a HTTP URL + @param options A mask to specify options to use for this request + @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + @param completedBlock A block called when operation has been completed. + @return An operation which allow the user to cancel the current request. + */ +- (nullable id)loadImageDataWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageLoaderProgressBlock)progressBlock + completed:(nullable SDWebImageLoaderDataCompletedBlock)completedBlock; + +@end diff --git a/SDWebImage/SDWebImageLoader.m b/SDWebImage/SDWebImageLoader.m new file mode 100644 index 00000000..2f669be0 --- /dev/null +++ b/SDWebImage/SDWebImageLoader.m @@ -0,0 +1,9 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageLoader.h" diff --git a/SDWebImage/SDWebImageLoadersManager.h b/SDWebImage/SDWebImageLoadersManager.h new file mode 100644 index 00000000..7e070f2c --- /dev/null +++ b/SDWebImage/SDWebImageLoadersManager.h @@ -0,0 +1,34 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageLoader.h" + +@interface SDWebImageLoadersManager : NSObject + +@property (nonatomic, class, readonly, nonnull) SDWebImageLoadersManager *sharedManager; + +/** + All image loaders in manager. The loaders array is a priority queue, which means the later added loader will have the highest priority + */ +@property (nonatomic, strong, readwrite, nullable) NSArray>* loaders; + +/** + Add a new image loader to the end of loaders array. Which has the highest priority. + + @param loader loader + */ +- (void)addLoader:(nonnull id)loader; + +/** + Remove a image loader in the loaders array. + + @param loader loader + */ +- (void)removeLoader:(nonnull id)loader; + +@end diff --git a/SDWebImage/SDWebImageLoadersManager.m b/SDWebImage/SDWebImageLoadersManager.m new file mode 100644 index 00000000..8343b12b --- /dev/null +++ b/SDWebImage/SDWebImageLoadersManager.m @@ -0,0 +1,112 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageLoadersManager.h" +#import "SDWebImageDownloader.h" + +#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); +#define UNLOCK(lock) dispatch_semaphore_signal(lock); + +@interface SDWebImageLoadersManager () + +@property (strong, nonatomic, nonnull) NSMutableArray> *mutableLoaders; +@property (nonatomic, strong, nonnull) dispatch_semaphore_t loadersLock; + +@end + +@implementation SDWebImageLoadersManager + ++ (SDWebImageLoadersManager *)sharedManager { + static dispatch_once_t onceToken; + static SDWebImageLoadersManager *manager; + dispatch_once(&onceToken, ^{ + manager = [[SDWebImageLoadersManager alloc] init]; + }); + return manager; +} + +- (instancetype)init { + self = [super init]; + if (self) { + // initialize with default image loaders + self.mutableLoaders = [@[[SDWebImageDownloader sharedDownloader]] mutableCopy]; + self.loadersLock = dispatch_semaphore_create(1); + } + return self; +} + +#pragma mark - Loader Property + +- (void)addLoader:(id)loader { + if ([loader conformsToProtocol:@protocol(SDWebImageLoader)]) { + LOCK(self.loadersLock); + [self.mutableLoaders addObject:loader]; + UNLOCK(self.loadersLock); + } +} + +- (void)removeLoader:(id)loader { + LOCK(self.loadersLock); + [self.mutableLoaders removeObject:loader]; + UNLOCK(self.loadersLock); +} + +- (NSArray> *)loaders { + NSArray> *sortedLoaders; + LOCK(self.loadersLock); + sortedLoaders = [[[self.mutableLoaders copy] reverseObjectEnumerator] allObjects]; + UNLOCK(self.loadersLock); + return sortedLoaders; +} + +- (void)setLoaders:(NSArray> *)loaders { + LOCK(self.loadersLock); + self.mutableLoaders = [loaders mutableCopy]; + UNLOCK(self.loadersLock); +} + +#pragma mark - SDWebImageLoader + +- (BOOL)canLoadWithURL:(nullable NSURL *)url { + for (id loader in self.loaders) { + if ([loader canLoadWithURL:url]) { + return YES; + } + } + return NO; +} + +- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDWebImageLoaderProgressBlock)progressBlock completed:(SDWebImageLoaderCompletedBlock)completedBlock { + if (!url) { + return nil; + } + for (id loader in self.loaders) { + if ([loader respondsToSelector:@selector(loadImageWithURL:options:context:progress:completed:)]) { + if ([loader canLoadWithURL:url]) { + return [loader loadImageWithURL:url options:options context:context progress:progressBlock completed:completedBlock]; + } + } + } + return nil; +} + +- (id)loadImageDataWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDWebImageLoaderProgressBlock)progressBlock completed:(SDWebImageLoaderDataCompletedBlock)completedBlock { + if (!url) { + return nil; + } + for (id loader in self.loaders) { + if ([loader respondsToSelector:@selector(loadImageDataWithURL:options:context:progress:completed:)]) { + if ([loader canLoadWithURL:url]) { + return [loader loadImageDataWithURL:url options:options context:context progress:progressBlock completed:completedBlock]; + } + } + } + return nil; +} + +@end diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 6f338d95..39c31f3c 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -13,6 +13,7 @@ #import "SDWebImageTransformer.h" #import "SDWebImageCacheKeyFilter.h" #import "SDWebImageCacheSerializer.h" +#import "SDWebImageLoader.h" typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL); @@ -105,7 +106,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; * The image downloader used by manager to download image. * @note If you specify a non-shared downloader, don't forget to call `invalidateSessionAndCancel:` at proper time to avoid memory leak. */ -@property (strong, nonatomic, readonly, nonnull) SDWebImageDownloader *imageDownloader; +@property (strong, nonatomic, readonly, nonnull) id imageDownloader; /** The image transformer for manager. It's used for image transform after the image load finished and store the transformed image to cache, see `SDWebImageTransformer`. @@ -175,7 +176,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; * Allows to specify instance of cache and image downloader used with image manager. * @return new instance of `SDWebImageManager` with specified cache and downloader. */ -- (nonnull instancetype)initWithCache:(nonnull id)cache downloader:(nonnull SDWebImageDownloader *)downloader NS_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithCache:(nonnull id)cache downloader:(nonnull id)downloader NS_DESIGNATED_INITIALIZER; /** * Downloads the image at the given URL if not present in cache or return the cached version otherwise. diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 84c72340..c35bb07e 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -28,7 +28,7 @@ static SDWebImageDownloader *_defaultImageDownloader; @interface SDWebImageManager () @property (strong, nonatomic, readwrite, nonnull) SDImageCache *imageCache; -@property (strong, nonatomic, readwrite, nonnull) SDWebImageDownloader *imageDownloader; +@property (strong, nonatomic, readwrite, nonnull) id imageDownloader; @property (strong, nonatomic, nonnull) NSMutableSet *failedURLs; @property (strong, nonatomic, nonnull) NSMutableArray *runningOperations; @@ -79,7 +79,7 @@ static SDWebImageDownloader *_defaultImageDownloader; return [self initWithCache:cache downloader:downloader]; } -- (nonnull instancetype)initWithCache:(nonnull id)cache downloader:(nonnull SDWebImageDownloader *)downloader { +- (nonnull instancetype)initWithCache:(nonnull id)cache downloader:(nonnull id)downloader { if ((self = [super init])) { _imageCache = cache; _imageDownloader = downloader; @@ -201,30 +201,10 @@ static SDWebImageDownloader *_defaultImageDownloader; // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server. [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url]; } - - // download if no image or requested to refresh anyway, and download allowed by delegate - SDWebImageDownloaderOptions downloaderOptions = 0; - if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority; - if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload; - if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache; - if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground; - if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies; - if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates; - if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority; - if (options & SDWebImageScaleDownLargeImages) downloaderOptions |= SDWebImageDownloaderScaleDownLargeImages; - if (options & SDWebImageDecodeFirstFrameOnly) downloaderOptions |= SDWebImageDownloaderDecodeFirstFrameOnly; - if (options & SDWebImagePreloadAllFrames) downloaderOptions |= SDWebImageDownloaderPreloadAllFrames; - - if (cachedImage && options & SDWebImageRefreshCached) { - // force progressive off if image already cached but forced refreshing - downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload; - // ignore image read from NSURLCache if image if cached but force refreshing - downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse; - } // `SDWebImageCombinedOperation` -> `SDWebImageDownloadToken` -> `downloadOperationCancelToken`, which is a `SDCallbacksDictionary` and retain the completed block below, so we need weak-strong again to avoid retain cycle __weak typeof(strongOperation) weakSubOperation = strongOperation; - strongOperation.downloadOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions context:context progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { + strongOperation.downloadOperation = [self.imageDownloader loadImageWithURL:url options:options context:context progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { __strong typeof(weakSubOperation) strongSubOperation = weakSubOperation; if (!strongSubOperation || strongSubOperation.isCancelled) { // Do nothing if the operation was cancelled @@ -264,12 +244,6 @@ static SDWebImageDownloader *_defaultImageDownloader; if (options & SDWebImageCacheMemoryOnly) { storeCacheType = SDImageCacheTypeMemory; } - - // We've done the scale process in SDWebImageDownloader with the shared manager, this is used for custom manager and avoid extra scale. - if (self != [SDWebImageManager sharedManager] && cacheKeyFilter && downloadedImage && ![downloadedImage conformsToProtocol:@protocol(SDAnimatedImage)]) { - downloadedImage = [self scaledImageForKey:key image:downloadedImage]; - } - if (options & SDWebImageRefreshCached && cachedImage && !downloadedImage) { // Image refresh hit the NSURLCache cache, do not call the completion block } else if (downloadedImage && (!downloadedImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage)) && transformer) { diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index a98f0e97..bdc2df13 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -36,6 +36,8 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import +#import +#import #import #import #import From 8292c0c1e9c669c3b8c2dcf139706ce4d9c722da Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 16 Apr 2018 00:23:03 +0800 Subject: [PATCH 148/361] Update the loader protocol to refactor the common image decoding process. --- SDWebImage/SDWebImageDownloader.m | 8 +- SDWebImage/SDWebImageDownloaderOperation.m | 99 ++++--------------- SDWebImage/SDWebImageLoader.h | 41 +++++++- SDWebImage/SDWebImageLoader.m | 106 +++++++++++++++++++++ SDWebImage/SDWebImageManager.m | 12 ++- 5 files changed, 176 insertions(+), 90 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index d17a6b54..f42568c2 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -489,7 +489,11 @@ didReceiveResponse:(NSURLResponse *)response return YES; } -- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageLoaderProgressBlock)progressBlock completed:(SDWebImageLoaderCompletedBlock)completedBlock context:(SDWebImageContext *)context { +- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDWebImageLoaderProgressBlock)progressBlock completed:(SDWebImageLoaderCompletedBlock)completedBlock { + UIImage *cachedImage; + if ([context valueForKey:SDWebImageContextLoaderCachedImage]) { + cachedImage = [context valueForKey:SDWebImageContextLoaderCachedImage]; + } SDWebImageDownloaderOptions downloaderOptions = 0; if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority; if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload; @@ -500,7 +504,7 @@ didReceiveResponse:(NSURLResponse *)response if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority; if (options & SDWebImageScaleDownLargeImages) downloaderOptions |= SDWebImageDownloaderScaleDownLargeImages; - if (options & SDWebImageRefreshCached) { + if (cachedImage && options & SDWebImageRefreshCached) { // force progressive off if image already cached but forced refreshing downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload; // ignore image read from NSURLCache if image if cached but force refreshing diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 511cf8e2..db177345 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -7,12 +7,7 @@ */ #import "SDWebImageDownloaderOperation.h" -#import "SDWebImageManager.h" -#import "NSImage+Additions.h" -#import "UIImage+WebCache.h" #import "SDWebImageCodersManager.h" -#import "SDWebImageCoderHelper.h" -#import "SDAnimatedImage.h" #import "SDWebImageError.h" #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); @@ -46,7 +41,6 @@ typedef NSMutableDictionary SDCallbacksDictionary; @property (assign, nonatomic, getter = isFinished) BOOL finished; @property (strong, nonatomic, nullable) NSMutableData *imageData; @property (copy, nonatomic, nullable) NSData *cachedData; // for `SDWebImageDownloaderIgnoreCachedResponse` -@property (copy, nonatomic, nullable) NSString *cacheKey; @property (assign, nonatomic, readwrite) NSUInteger expectedSize; @property (strong, nonatomic, nullable, readwrite) NSURLResponse *response; @@ -357,42 +351,11 @@ didReceiveResponse:(NSURLResponse *)response } } } - [self.progressiveCoder updateIncrementalData:imageData finished:finished]; // progressive decode the image in coder queue dispatch_async(self.coderQueue, ^{ - // check whether we should use `SDAnimatedImage` - UIImage *image; - BOOL decodeFirstFrame = self.options & SDWebImageDownloaderDecodeFirstFrameOnly; - NSNumber *scaleValue = [self.context valueForKey:SDWebImageContextImageScaleFactor]; - CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(self.cacheKey); - if (!decodeFirstFrame) { - // check whether we should use `SDAnimatedImage` - if ([self.context valueForKey:SDWebImageContextAnimatedImageClass]) { - Class animatedImageClass = [self.context valueForKey:SDWebImageContextAnimatedImageClass]; - if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)] && [self.progressiveCoder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { - image = [[animatedImageClass alloc] initWithAnimatedCoder:(id)self.progressiveCoder scale:scale]; - } - } - } - if (!image) { - image = [self.progressiveCoder incrementalDecodedImageWithOptions:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; - } + UIImage *image = SDWebImageLoaderDecodeProgressiveImageData(data, self.request.URL, finished, self.progressiveCoder, [[self class] imageOptionsFromDownloaderOptions:self.options], [[self class] imageContextFromDownloadContext:self.context]); if (image) { - BOOL shouldDecode = (self.options & SDWebImageDownloaderAvoidDecodeImage) == 0; - if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { - // `SDAnimatedImage` do not decode - shouldDecode = NO; - } else if (image.sd_isAnimated) { - // animated image do not decode - shouldDecode = NO; - } - if (shouldDecode) { - image = [SDWebImageCoderHelper decodedImageWithImage:image]; - } - // mark the image as progressive (completionBlock one are not mark as progressive) - image.sd_isIncremental = YES; - // We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding. [self callCompletionBlocksWithImage:image imageData:nil error:nil finished:NO]; @@ -456,46 +419,7 @@ didReceiveResponse:(NSURLResponse *)response } else { // decode the image in coder queue dispatch_async(self.coderQueue, ^{ - BOOL decodeFirstFrame = self.options & SDWebImageDownloaderDecodeFirstFrameOnly; - NSNumber *scaleValue = [self.context valueForKey:SDWebImageContextImageScaleFactor]; - CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(self.cacheKey); - if (scale < 1) { - scale = 1; - } - UIImage *image; - if (!decodeFirstFrame) { - // check whether we should use `SDAnimatedImage` - if ([self.context valueForKey:SDWebImageContextAnimatedImageClass]) { - Class animatedImageClass = [self.context valueForKey:SDWebImageContextAnimatedImageClass]; - if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { - image = [[animatedImageClass alloc] initWithData:imageData scale:scale]; - if (self.options & SDWebImageDownloaderPreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { - [((id)image) preloadAllFrames]; - } - } - } - } - if (!image) { - image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; - } - - BOOL shouldDecode = (self.options & SDWebImageDownloaderAvoidDecodeImage) == 0; - if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { - // `SDAnimatedImage` do not decode - shouldDecode = NO; - } else if (image.sd_isAnimated) { - // animated image do not decode - shouldDecode = NO; - } - - if (shouldDecode) { - BOOL shouldScaleDown = self.options & SDWebImageDownloaderScaleDownLargeImages; - if (shouldScaleDown) { - image = [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; - } else { - image = [SDWebImageCoderHelper decodedImageWithImage:image]; - } - } + UIImage *image = SDWebImageLoaderDecodeImageData(imageData, self.request.URL, nil, [[self class] imageOptionsFromDownloaderOptions:self.options], [[self class] imageContextFromDownloadContext:self.context]); CGSize imageSize = image.size; if (imageSize.width == 0 || imageSize.height == 0) { [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}]]; @@ -546,11 +470,22 @@ didReceiveResponse:(NSURLResponse *)response } #pragma mark Helper methods -- (NSString *)cacheKey { - if (!_cacheKey) { - _cacheKey = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; ++ (SDWebImageOptions)imageOptionsFromDownloaderOptions:(SDWebImageDownloaderOptions)downloadOptions { + SDWebImageOptions options = 0; + if (downloadOptions & SDWebImageDownloaderScaleDownLargeImages) options |= SDWebImageScaleDownLargeImages; + if (downloadOptions & SDWebImageDownloaderDecodeFirstFrameOnly) options |= SDWebImageDecodeFirstFrameOnly; + if (downloadOptions & SDWebImageDownloaderPreloadAllFrames) options |= SDWebImagePreloadAllFrames; + + return options; +} + ++ (SDWebImageContext *)imageContextFromDownloadContext:(SDWebImageContext *)downloadContext { + SDWebImageContext *context = nil; + if (!downloadContext) { + return context; } - return _cacheKey; + + return context; } - (BOOL)shouldContinueWhenAppEntersBackground { diff --git a/SDWebImage/SDWebImageLoader.h b/SDWebImage/SDWebImageLoader.h index 6c891b6b..59a432b5 100644 --- a/SDWebImage/SDWebImageLoader.h +++ b/SDWebImage/SDWebImageLoader.h @@ -14,19 +14,50 @@ typedef void(^SDWebImageLoaderProgressBlock)(NSInteger receivedSize, NSInteger e typedef void(^SDWebImageLoaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished); typedef void(^SDWebImageLoaderDataCompletedBlock)(NSData * _Nullable data, NSError * _Nullable error, BOOL finished); +@protocol SDWebImageCoder, SDWebImageProgressiveCoder; + /** - A `SDImageCacheType` value to specify the cache type information from manager. `SDWebImageManager` will firstly query cache, then if cache miss or `SDWebImageRefreshCached` is set, it will start image loader to load the image. - This can be a hint for image loader to load the image from network and refresh the image from remote location if needed. (NSNumber) + This is the built-in decoding process for image download from network or local file. + @note If you want to implement your custom loader with `loadImageWithURL:options:context:progress:completed:` API, but also want to keep compatible with SDWebImage's behavior, you'd better use this to produce image. + + @param imageData The image data from the network. Should not be nil + @param imageURL The image URL from the input. Should not be nil + @param coder The image coder. You can pass nil to use the default `SDWebImageCodersManager`. See `SDWebImageCoder` + @param options The options arg from the input + @param context The context arg from the input + @return The decoded image for current image data load from the network */ -FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextLoaderCacheType; +FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, id _Nullable coder, SDWebImageOptions options, SDWebImageContext * _Nullable context); + +/** + This is the built-in decoding process for image progressive download from network. It's used when `SDWebImageProgressiveDownload` option is set. + @note If you want to implement your custom loader with `loadImageWithURL:options:context:progress:completed:` API, but also want to keep compatible with SDWebImage's behavior, you'd better use this to produce image. + + @param imageData The image data from the network so far. Should not be nil + @param imageURL The image URL from the input. Should not be nil + @param finished Pass NO to specify the download process has not finished. Pass YES when all image data has finished. + @param progressiveCoder The image progressive coder. Should not be nil. You should bind the progressive coder for each of loading operation to avoid conflict. See `SDWebImageProgressiveCoder`. + @param options The options arg from the input + @param context The context arg from the input + @return The decoded progressive image for current image data load from the network + */ +FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, BOOL finished, id _Nonnull progressiveCoder, SDWebImageOptions options, SDWebImageContext * _Nullable context); + +/** + A `UIImage` instance from `SDWebImageManager` when you specify `SDWebImageRefreshCached` and image cache hit. + This can be a hint for image loader to load the image from network and refresh the image from remote location if needed. If the cached image is equal to the remote location one. you should call the completion with all nil args. (UIImage) + */ +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextLoaderCachedImage; + +#pragma mark - SDWebImageLoader @protocol SDWebImageLoader - (BOOL)canLoadWithURL:(nullable NSURL *)url; // We provide two ways to allow a image loader to load the image. -// The first one should return the `UIImage` image instance as well as `NSData` image data. This is suitable for the use case such as progressive download from network, or image directlly from Photos framework. -// The second one should return just the `NSData` image data, we will use the common image decoding logic to process the correct image instance, so the image loader itself can concentrate on only data retriving. This is suitable for the use case such as load the data from file. +// The first one should return the `UIImage` image instance as well as `NSData` image data. This is suitable for the use case such as image from third-party SDKs, such as image directlly from Photos framework. +// The second one should return just the `NSData` image data, we will use the common image decoding logic to process the correct image instance, so the image loader itself can concentrate on only data retriving. This is suitable for the use case such as load the data from network or local file. // Your image loader **MUST** implement at least one of those protocol, or an assert will occur. We will firstlly ask for `loadImageWithURL:options:progress:completed:context:` if you implement it. If this one return nil, we will continue to ask for `loadImageDataWithURL:options:progress:completed:context:` if you implement it. // @note It's your responsibility to load the image in the desired global queue(to avoid block main queue). We do not dispatch these method call in a global queue but just from the call queue (For `SDWebImageManager`, it typically call from the main queue). diff --git a/SDWebImage/SDWebImageLoader.m b/SDWebImage/SDWebImageLoader.m index 2f669be0..ce00b1d6 100644 --- a/SDWebImage/SDWebImageLoader.m +++ b/SDWebImage/SDWebImageLoader.m @@ -7,3 +7,109 @@ */ #import "SDWebImageLoader.h" +#import "SDWebImageCodersManager.h" +#import "SDWebImageCoderHelper.h" +#import "SDAnimatedImage.h" +#import "UIImage+WebCache.h" + +UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, id _Nullable coder, SDWebImageOptions options, SDWebImageContext * _Nullable context) { + NSCParameterAssert(imageData); + NSCParameterAssert(imageURL); + + UIImage *image; + NSString *cacheKey = imageURL.absoluteString; + BOOL decodeFirstFrame = options & SDWebImageDecodeFirstFrameOnly; + NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor]; + CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); + if (scale < 1) { + scale = 1; + } + if (!coder) { + coder = [SDWebImageCodersManager sharedManager]; + } + + if (!decodeFirstFrame) { + // check whether we should use `SDAnimatedImage` + if ([context valueForKey:SDWebImageContextAnimatedImageClass]) { + Class animatedImageClass = [context valueForKey:SDWebImageContextAnimatedImageClass]; + if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { + image = [[animatedImageClass alloc] initWithData:imageData scale:scale]; + if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { + [((id)image) preloadAllFrames]; + } + } + } + } + if (!image) { + image = [coder decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; + } + if (image) { + BOOL shouldDecode = YES; + if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { + // `SDAnimatedImage` do not decode + shouldDecode = NO; + } else if (image.sd_isAnimated) { + // animated image do not decode + shouldDecode = NO; + } + + if (shouldDecode) { + BOOL shouldScaleDown = options & SDWebImageScaleDownLargeImages; + if (shouldScaleDown) { + image = [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; + } else { + image = [SDWebImageCoderHelper decodedImageWithImage:image]; + } + } + } + + return image; +} + +UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, BOOL finished, id _Nonnull progressiveCoder, SDWebImageOptions options, SDWebImageContext * _Nullable context) { + NSCParameterAssert(imageData); + NSCParameterAssert(imageURL); + NSCParameterAssert(progressiveCoder); + + UIImage *image; + NSString *cacheKey = imageURL.absoluteString; + BOOL decodeFirstFrame = options & SDWebImageDecodeFirstFrameOnly; + NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor]; + CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); + if (scale < 1) { + scale = 1; + } + + [progressiveCoder updateIncrementalData:imageData finished:finished]; + if (!decodeFirstFrame) { + // check whether we should use `SDAnimatedImage` + if ([context valueForKey:SDWebImageContextAnimatedImageClass]) { + Class animatedImageClass = [context valueForKey:SDWebImageContextAnimatedImageClass]; + if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)] && [progressiveCoder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { + image = [[animatedImageClass alloc] initWithAnimatedCoder:(id)progressiveCoder scale:scale]; + } + } + } + if (!image) { + image = [progressiveCoder incrementalDecodedImageWithOptions:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; + } + if (image) { + BOOL shouldDecode = YES; + if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { + // `SDAnimatedImage` do not decode + shouldDecode = NO; + } else if (image.sd_isAnimated) { + // animated image do not decode + shouldDecode = NO; + } + if (shouldDecode) { + image = [SDWebImageCoderHelper decodedImageWithImage:image]; + } + // mark the image as progressive (completionBlock one are not mark as progressive) + image.sd_isIncremental = YES; + } + + return image; +} + +SDWebImageContextOption const SDWebImageContextLoaderCachedImage = @"loaderCachedImage"; diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index c35bb07e..09c9522a 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -196,15 +196,25 @@ static SDWebImageDownloader *_defaultImageDownloader; && (!cachedImage || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]); if (shouldDownload) { + SDWebImageContext *downloadContext = context; if (cachedImage && options & SDWebImageRefreshCached) { // If image was found in the cache but SDWebImageRefreshCached is provided, notify about the cached image // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server. [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url]; + // Pass the cached image to the image loader. The image loader should check whether the remote image is equal to the cached image. + SDWebImageMutableContext *mutableContext; + if (downloadContext) { + mutableContext = [downloadContext mutableCopy]; + } else { + mutableContext = [NSMutableDictionary dictionary]; + } + [mutableContext setValue:cachedImage forKey:SDWebImageContextLoaderCachedImage]; + downloadContext = [mutableContext copy]; } // `SDWebImageCombinedOperation` -> `SDWebImageDownloadToken` -> `downloadOperationCancelToken`, which is a `SDCallbacksDictionary` and retain the completed block below, so we need weak-strong again to avoid retain cycle __weak typeof(strongOperation) weakSubOperation = strongOperation; - strongOperation.downloadOperation = [self.imageDownloader loadImageWithURL:url options:options context:context progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { + strongOperation.downloadOperation = [self.imageDownloader loadImageWithURL:url options:options context:downloadContext progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { __strong typeof(weakSubOperation) strongSubOperation = weakSubOperation; if (!strongSubOperation || strongSubOperation.isCancelled) { // Do nothing if the operation was cancelled From 60759f812a4ac2c178b0a55579c73f6f55917745 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 16 Apr 2018 17:14:13 +0800 Subject: [PATCH 149/361] Refactor to only use one publish protocol for custom loader. Renaming image downloader description to loader --- SDWebImage/SDWebImageDownloader.h | 5 +- SDWebImage/SDWebImageDownloaderOperation.m | 18 +++---- SDWebImage/SDWebImageLoader.h | 59 +++++++++------------- SDWebImage/SDWebImageLoader.m | 29 +++++++---- SDWebImage/SDWebImageLoadersManager.m | 14 ----- SDWebImage/SDWebImageManager.h | 15 +++--- SDWebImage/SDWebImageManager.m | 41 ++++++++++----- Tests/Tests/SDWebImageManagerTests.m | 2 +- 8 files changed, 88 insertions(+), 95 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 37050719..03622749 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -248,8 +248,9 @@ typedef SDWebImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock; /** - SDWebImageDownloader is the built-in image downloader conform to `SDWebImageLoader`. Which provide the HTTP/HTTPS/FTP download, or local file URL using NSURLSession. - However, this downloader does also support customization for advanced users. You can specify `operationClass` in download config to custom download operation, See `SDWebImageDownloaderOperation`. + SDWebImageDownloader is the built-in image loader conform to `SDWebImageLoader`. Which provide the HTTP/HTTPS/FTP download, or local file URL using NSURLSession. + However, this downloader class itself also support customization for advanced users. You can specify `operationClass` in download config to custom download operation, See `SDWebImageDownloaderOperation`. + If you want to provide some image loader which beyond network or local file, consider to create your own custom class conform to `SDWebImageLoader`. */ @interface SDWebImageDownloader (SDWebImageLoader) diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index db177345..0c7c1747 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -350,11 +350,15 @@ didReceiveResponse:(NSURLResponse *)response break; } } + // If we can't find any progressive coder, disable progressive download + if (!self.progressiveCoder) { + self.options &= ~SDWebImageDownloaderProgressiveDownload; + } } // progressive decode the image in coder queue dispatch_async(self.coderQueue, ^{ - UIImage *image = SDWebImageLoaderDecodeProgressiveImageData(data, self.request.URL, finished, self.progressiveCoder, [[self class] imageOptionsFromDownloaderOptions:self.options], [[self class] imageContextFromDownloadContext:self.context]); + UIImage *image = SDWebImageLoaderDecodeProgressiveImageData(data, self.request.URL, finished, self.progressiveCoder, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); if (image) { // We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding. @@ -419,7 +423,7 @@ didReceiveResponse:(NSURLResponse *)response } else { // decode the image in coder queue dispatch_async(self.coderQueue, ^{ - UIImage *image = SDWebImageLoaderDecodeImageData(imageData, self.request.URL, nil, [[self class] imageOptionsFromDownloaderOptions:self.options], [[self class] imageContextFromDownloadContext:self.context]); + UIImage *image = SDWebImageLoaderDecodeImageData(imageData, self.request.URL, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); CGSize imageSize = image.size; if (imageSize.width == 0 || imageSize.height == 0) { [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}]]; @@ -475,19 +479,11 @@ didReceiveResponse:(NSURLResponse *)response if (downloadOptions & SDWebImageDownloaderScaleDownLargeImages) options |= SDWebImageScaleDownLargeImages; if (downloadOptions & SDWebImageDownloaderDecodeFirstFrameOnly) options |= SDWebImageDecodeFirstFrameOnly; if (downloadOptions & SDWebImageDownloaderPreloadAllFrames) options |= SDWebImagePreloadAllFrames; + if (downloadOptions & SDWebImageDownloaderAvoidDecodeImage) options |= SDWebImageAvoidDecodeImage; return options; } -+ (SDWebImageContext *)imageContextFromDownloadContext:(SDWebImageContext *)downloadContext { - SDWebImageContext *context = nil; - if (!downloadContext) { - return context; - } - - return context; -} - - (BOOL)shouldContinueWhenAppEntersBackground { return self.options & SDWebImageDownloaderContinueInBackground; } diff --git a/SDWebImage/SDWebImageLoader.h b/SDWebImage/SDWebImageLoader.h index 59a432b5..dbc9ad02 100644 --- a/SDWebImage/SDWebImageLoader.h +++ b/SDWebImage/SDWebImageLoader.h @@ -10,11 +10,19 @@ #import "SDWebImageDefine.h" #import "SDWebImageOperation.h" +@protocol SDWebImageProgressiveCoder; typedef void(^SDWebImageLoaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL); typedef void(^SDWebImageLoaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished); -typedef void(^SDWebImageLoaderDataCompletedBlock)(NSData * _Nullable data, NSError * _Nullable error, BOOL finished); -@protocol SDWebImageCoder, SDWebImageProgressiveCoder; +#pragma mark - Context + +/** + A `UIImage` instance from `SDWebImageManager` when you specify `SDWebImageRefreshCached` and image cache hit. + This can be a hint for image loader to load the image from network and refresh the image from remote location if needed. If the cached image is equal to the remote location one. you should call the completion with all nil args. (UIImage) + */ +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextLoaderCachedImage; + +#pragma mark - Helper method /** This is the built-in decoding process for image download from network or local file. @@ -22,15 +30,14 @@ typedef void(^SDWebImageLoaderDataCompletedBlock)(NSData * _Nullable data, NSErr @param imageData The image data from the network. Should not be nil @param imageURL The image URL from the input. Should not be nil - @param coder The image coder. You can pass nil to use the default `SDWebImageCodersManager`. See `SDWebImageCoder` @param options The options arg from the input @param context The context arg from the input @return The decoded image for current image data load from the network */ -FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, id _Nullable coder, SDWebImageOptions options, SDWebImageContext * _Nullable context); +FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, SDWebImageOptions options, SDWebImageContext * _Nullable context); /** - This is the built-in decoding process for image progressive download from network. It's used when `SDWebImageProgressiveDownload` option is set. + This is the built-in decoding process for image progressive download from network. It's used when `SDWebImageProgressiveDownload` option is set. (It's not required when your loader does not support progressive image loading) @note If you want to implement your custom loader with `loadImageWithURL:options:context:progress:completed:` API, but also want to keep compatible with SDWebImage's behavior, you'd better use this to produce image. @param imageData The image data from the network so far. Should not be nil @@ -43,25 +50,24 @@ FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _ */ FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, BOOL finished, id _Nonnull progressiveCoder, SDWebImageOptions options, SDWebImageContext * _Nullable context); -/** - A `UIImage` instance from `SDWebImageManager` when you specify `SDWebImageRefreshCached` and image cache hit. - This can be a hint for image loader to load the image from network and refresh the image from remote location if needed. If the cached image is equal to the remote location one. you should call the completion with all nil args. (UIImage) - */ -FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextLoaderCachedImage; - #pragma mark - SDWebImageLoader +// This is the protocol to specify custom image load process. You can create your own class to conform this protocol and use as a image loader to load image from network or any avaiable remote resources defined by yourself. +// If you want to implement custom loader for image download from network or local file, you just need to concentrate on image data download only. After the download finish, call `SDWebImageLoaderDecodeImageData` or `SDWebImageLoaderDecodeProgressiveImageData` to use the built-in decoding process and produce image (Remember to call in the global queue). And finally callback the completion block. +// If you directlly get the image instance using some third-party SDKs, such as image directlly from Photos framework. You can process the image data and image instance by yourself without that built-in decoding process. And finally callback the completion block. +// @note It's your responsibility to load the image in the desired global queue(to avoid block main queue). We do not dispatch these method call in a global queue but just from the call queue (For `SDWebImageManager`, it typically call from the main queue). + @protocol SDWebImageLoader +/** + Whether current image loader supports to load the provide image URL. + This will be checked everytime a new image request come for loader. If this return NO, we will mark this image load as failed. If return YES, we will start to call `loadImageWithURL:options:context:progress:completed:`. + + @param url The image URL to be loaded. + @return YES to continue download, NO to stop download. + */ - (BOOL)canLoadWithURL:(nullable NSURL *)url; -// We provide two ways to allow a image loader to load the image. -// The first one should return the `UIImage` image instance as well as `NSData` image data. This is suitable for the use case such as image from third-party SDKs, such as image directlly from Photos framework. -// The second one should return just the `NSData` image data, we will use the common image decoding logic to process the correct image instance, so the image loader itself can concentrate on only data retriving. This is suitable for the use case such as load the data from network or local file. -// Your image loader **MUST** implement at least one of those protocol, or an assert will occur. We will firstlly ask for `loadImageWithURL:options:progress:completed:context:` if you implement it. If this one return nil, we will continue to ask for `loadImageDataWithURL:options:progress:completed:context:` if you implement it. -// @note It's your responsibility to load the image in the desired global queue(to avoid block main queue). We do not dispatch these method call in a global queue but just from the call queue (For `SDWebImageManager`, it typically call from the main queue). - -@optional /** Load the image and image data with the given URL and return the image data. You're responsible for producing the image instance. @@ -79,21 +85,4 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextLoader progress:(nullable SDWebImageLoaderProgressBlock)progressBlock completed:(nullable SDWebImageLoaderCompletedBlock)completedBlock; -/** - Load the image with the given URL and return the image data. We will automatically handler the image decoding stuff for you. - - @param url The URL represent the image. Note this may not be a HTTP URL - @param options A mask to specify options to use for this request - @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. - @param progressBlock A block called while image is downloading - * @note the progress block is executed on a background queue - @param completedBlock A block called when operation has been completed. - @return An operation which allow the user to cancel the current request. - */ -- (nullable id)loadImageDataWithURL:(nullable NSURL *)url - options:(SDWebImageOptions)options - context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageLoaderProgressBlock)progressBlock - completed:(nullable SDWebImageLoaderDataCompletedBlock)completedBlock; - @end diff --git a/SDWebImage/SDWebImageLoader.m b/SDWebImage/SDWebImageLoader.m index ce00b1d6..c26fda1b 100644 --- a/SDWebImage/SDWebImageLoader.m +++ b/SDWebImage/SDWebImageLoader.m @@ -7,27 +7,30 @@ */ #import "SDWebImageLoader.h" +#import "SDWebImageCacheKeyFilter.h" #import "SDWebImageCodersManager.h" #import "SDWebImageCoderHelper.h" #import "SDAnimatedImage.h" #import "UIImage+WebCache.h" -UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, id _Nullable coder, SDWebImageOptions options, SDWebImageContext * _Nullable context) { +UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, SDWebImageOptions options, SDWebImageContext * _Nullable context) { NSCParameterAssert(imageData); NSCParameterAssert(imageURL); UIImage *image; - NSString *cacheKey = imageURL.absoluteString; + id cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter]; + NSString *cacheKey; + if (cacheKeyFilter) { + cacheKey = [cacheKeyFilter cacheKeyForURL:imageURL]; + } else { + cacheKey = imageURL.absoluteString; + } BOOL decodeFirstFrame = options & SDWebImageDecodeFirstFrameOnly; NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor]; CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); if (scale < 1) { scale = 1; } - if (!coder) { - coder = [SDWebImageCodersManager sharedManager]; - } - if (!decodeFirstFrame) { // check whether we should use `SDAnimatedImage` if ([context valueForKey:SDWebImageContextAnimatedImageClass]) { @@ -41,10 +44,10 @@ UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, } } if (!image) { - image = [coder decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; + image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; } if (image) { - BOOL shouldDecode = YES; + BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { // `SDAnimatedImage` do not decode shouldDecode = NO; @@ -72,7 +75,13 @@ UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull NSCParameterAssert(progressiveCoder); UIImage *image; - NSString *cacheKey = imageURL.absoluteString; + id cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter]; + NSString *cacheKey; + if (cacheKeyFilter) { + cacheKey = [cacheKeyFilter cacheKeyForURL:imageURL]; + } else { + cacheKey = imageURL.absoluteString; + } BOOL decodeFirstFrame = options & SDWebImageDecodeFirstFrameOnly; NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor]; CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); @@ -94,7 +103,7 @@ UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull image = [progressiveCoder incrementalDecodedImageWithOptions:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; } if (image) { - BOOL shouldDecode = YES; + BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { // `SDAnimatedImage` do not decode shouldDecode = NO; diff --git a/SDWebImage/SDWebImageLoadersManager.m b/SDWebImage/SDWebImageLoadersManager.m index 8343b12b..8b5ea363 100644 --- a/SDWebImage/SDWebImageLoadersManager.m +++ b/SDWebImage/SDWebImageLoadersManager.m @@ -95,18 +95,4 @@ return nil; } -- (id)loadImageDataWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDWebImageLoaderProgressBlock)progressBlock completed:(SDWebImageLoaderDataCompletedBlock)completedBlock { - if (!url) { - return nil; - } - for (id loader in self.loaders) { - if ([loader respondsToSelector:@selector(loadImageDataWithURL:options:context:progress:completed:)]) { - if ([loader canLoadWithURL:url]) { - return [loader loadImageDataWithURL:url options:options context:context progress:progressBlock completed:completedBlock]; - } - } - } - return nil; -} - @end diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 39c31f3c..c9112984 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -103,10 +103,9 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; @property (strong, nonatomic, readonly, nonnull) id imageCache; /** - * The image downloader used by manager to download image. - * @note If you specify a non-shared downloader, don't forget to call `invalidateSessionAndCancel:` at proper time to avoid memory leak. + * The image loader used by manager to load image. */ -@property (strong, nonatomic, readonly, nonnull) id imageDownloader; +@property (strong, nonatomic, readonly, nonnull) id imageLoader; /** The image transformer for manager. It's used for image transform after the image load finished and store the transformed image to cache, see `SDWebImageTransformer`. @@ -162,10 +161,10 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; @property (nonatomic, class, nullable) id defaultImageCache; /** - The default image downloader for manager which is created with no arguments. Such as shared manager or init. + The default image loader for manager which is created with no arguments. Such as shared manager or init. Defaults to nil. Means using `SDWebImageDownloader.sharedDownloader` */ -@property (nonatomic, class, nullable) SDWebImageDownloader *defaultImageDownloader; +@property (nonatomic, class, nullable) id defaultImageLoader; /** * Returns global shared manager instance. @@ -173,10 +172,10 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; @property (nonatomic, class, readonly, nonnull) SDWebImageManager *sharedManager; /** - * Allows to specify instance of cache and image downloader used with image manager. - * @return new instance of `SDWebImageManager` with specified cache and downloader. + * Allows to specify instance of cache and image loader used with image manager. + * @return new instance of `SDWebImageManager` with specified cache and loader. */ -- (nonnull instancetype)initWithCache:(nonnull id)cache downloader:(nonnull id)downloader NS_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithCache:(nonnull id)cache loader:(nonnull id)loader NS_DESIGNATED_INITIALIZER; /** * Downloads the image at the given URL if not present in cache or return the cached version otherwise. diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 09c9522a..3b0e4ef8 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -14,7 +14,7 @@ #import "SDWebImageError.h" static id _defaultImageCache; -static SDWebImageDownloader *_defaultImageDownloader; +static id _defaultImageLoader; @interface SDWebImageCombinedOperation () @@ -28,7 +28,7 @@ static SDWebImageDownloader *_defaultImageDownloader; @interface SDWebImageManager () @property (strong, nonatomic, readwrite, nonnull) SDImageCache *imageCache; -@property (strong, nonatomic, readwrite, nonnull) id imageDownloader; +@property (strong, nonatomic, readwrite, nonnull) id imageLoader; @property (strong, nonatomic, nonnull) NSMutableSet *failedURLs; @property (strong, nonatomic, nonnull) NSMutableArray *runningOperations; @@ -47,15 +47,15 @@ static SDWebImageDownloader *_defaultImageDownloader; _defaultImageCache = defaultImageCache; } -+ (SDWebImageDownloader *)defaultImageDownloader { - return _defaultImageDownloader; ++ (id)defaultImageLoader { + return _defaultImageLoader; } -+ (void)setDefaultImageDownloader:(SDWebImageDownloader *)defaultImageDownloader { - if (defaultImageDownloader && ![defaultImageDownloader isKindOfClass:[SDWebImageDownloader class]]) { ++ (void)setDefaultImageLoader:(id)defaultImageLoader { + if (defaultImageLoader && ![defaultImageLoader conformsToProtocol:@protocol(SDWebImageLoader)]) { return; } - _defaultImageDownloader = defaultImageDownloader; + _defaultImageLoader = defaultImageLoader; } + (nonnull instancetype)sharedManager { @@ -72,17 +72,17 @@ static SDWebImageDownloader *_defaultImageDownloader; if (!cache) { cache = [SDImageCache sharedImageCache]; } - SDWebImageDownloader *downloader = [[self class] defaultImageDownloader]; - if (!downloader) { - downloader = [SDWebImageDownloader sharedDownloader]; + id loader = [[self class] defaultImageLoader]; + if (!loader) { + loader = [SDWebImageDownloader sharedDownloader]; } - return [self initWithCache:cache downloader:downloader]; + return [self initWithCache:cache loader:loader]; } -- (nonnull instancetype)initWithCache:(nonnull id)cache downloader:(nonnull id)downloader { +- (nonnull instancetype)initWithCache:(nonnull id)cache loader:(nonnull id)loader { if ((self = [super init])) { _imageCache = cache; - _imageDownloader = downloader; + _imageLoader = loader; _failedURLs = [NSMutableSet new]; _runningOperations = [NSMutableArray new]; } @@ -195,8 +195,21 @@ static SDWebImageDownloader *_defaultImageDownloader; BOOL shouldDownload = (!(options & SDWebImageFromCacheOnly)) && (!cachedImage || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]); + // Check whether image downloader support target URL + shouldDownload &= [self.imageLoader canLoadWithURL:url]; if (shouldDownload) { SDWebImageContext *downloadContext = context; + if (cacheKeyFilter) { + // Pass the cache key filter to the image loader. + SDWebImageMutableContext *mutableContext; + if (downloadContext) { + mutableContext = [downloadContext mutableCopy]; + } else { + mutableContext = [NSMutableDictionary dictionary]; + } + [mutableContext setValue:cacheKeyFilter forKey:SDWebImageContextCacheKeyFilter]; + downloadContext = [mutableContext copy]; + } if (cachedImage && options & SDWebImageRefreshCached) { // If image was found in the cache but SDWebImageRefreshCached is provided, notify about the cached image // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server. @@ -214,7 +227,7 @@ static SDWebImageDownloader *_defaultImageDownloader; // `SDWebImageCombinedOperation` -> `SDWebImageDownloadToken` -> `downloadOperationCancelToken`, which is a `SDCallbacksDictionary` and retain the completed block below, so we need weak-strong again to avoid retain cycle __weak typeof(strongOperation) weakSubOperation = strongOperation; - strongOperation.downloadOperation = [self.imageDownloader loadImageWithURL:url options:options context:downloadContext progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { + strongOperation.downloadOperation = [self.imageLoader loadImageWithURL:url options:options context:downloadContext progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { __strong typeof(weakSubOperation) strongSubOperation = weakSubOperation; if (!strongSubOperation || strongSubOperation.isCancelled) { // Do nothing if the operation was cancelled diff --git a/Tests/Tests/SDWebImageManagerTests.m b/Tests/Tests/SDWebImageManagerTests.m index d9887199..3f2e397b 100644 --- a/Tests/Tests/SDWebImageManagerTests.m +++ b/Tests/Tests/SDWebImageManagerTests.m @@ -118,7 +118,7 @@ NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; NSString *testImagePath = [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; transformer.testImage = [[UIImage alloc] initWithContentsOfFile:testImagePath]; - SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:[SDImageCache sharedImageCache] downloader:[SDWebImageDownloader sharedDownloader]]; + SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:[SDImageCache sharedImageCache] loader:[SDWebImageDownloader sharedDownloader]]; manager.transformer = transformer; [[SDImageCache sharedImageCache] removeImageForKey:kTestJpegURL withCompletion:^{ [manager loadImageWithURL:imageURL options:SDWebImageTransformAnimatedImage progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { From d5074429f0fe03f441e615841c45d6ceac394cd4 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 21:03:33 +0800 Subject: [PATCH 150/361] Add tests for custom loader protocol, using a test loader to specify loader function --- SDWebImage/SDWebImageLoadersManager.h | 2 +- SDWebImage/SDWebImageLoadersManager.m | 52 +++++++++--------- .../project.pbxproj | 8 +++ Tests/Tests/SDWebImageDownloaderTests.m | 32 +++++++++++ Tests/Tests/SDWebImageTestLoader.h | 16 ++++++ Tests/Tests/SDWebImageTestLoader.m | 53 +++++++++++++++++++ 6 files changed, 136 insertions(+), 27 deletions(-) create mode 100644 Tests/Tests/SDWebImageTestLoader.h create mode 100644 Tests/Tests/SDWebImageTestLoader.m diff --git a/SDWebImage/SDWebImageLoadersManager.h b/SDWebImage/SDWebImageLoadersManager.h index 7e070f2c..7b59b592 100644 --- a/SDWebImage/SDWebImageLoadersManager.h +++ b/SDWebImage/SDWebImageLoadersManager.h @@ -15,7 +15,7 @@ /** All image loaders in manager. The loaders array is a priority queue, which means the later added loader will have the highest priority */ -@property (nonatomic, strong, readwrite, nullable) NSArray>* loaders; +@property (nonatomic, copy, readwrite, nullable) NSArray>* loaders; /** Add a new image loader to the end of loaders array. Which has the highest priority. diff --git a/SDWebImage/SDWebImageLoadersManager.m b/SDWebImage/SDWebImageLoadersManager.m index 8b5ea363..9e5850de 100644 --- a/SDWebImage/SDWebImageLoadersManager.m +++ b/SDWebImage/SDWebImageLoadersManager.m @@ -14,7 +14,6 @@ @interface SDWebImageLoadersManager () -@property (strong, nonatomic, nonnull) NSMutableArray> *mutableLoaders; @property (nonatomic, strong, nonnull) dispatch_semaphore_t loadersLock; @end @@ -34,7 +33,7 @@ self = [super init]; if (self) { // initialize with default image loaders - self.mutableLoaders = [@[[SDWebImageDownloader sharedDownloader]] mutableCopy]; + self.loaders = @[[SDWebImageDownloader sharedDownloader]]; self.loadersLock = dispatch_semaphore_create(1); } return self; @@ -43,37 +42,37 @@ #pragma mark - Loader Property - (void)addLoader:(id)loader { - if ([loader conformsToProtocol:@protocol(SDWebImageLoader)]) { - LOCK(self.loadersLock); - [self.mutableLoaders addObject:loader]; - UNLOCK(self.loadersLock); + if (![loader conformsToProtocol:@protocol(SDWebImageLoader)]) { + return; } + LOCK(self.loadersLock); + NSMutableArray> *mutableLoaders = [self.loaders mutableCopy]; + if (!mutableLoaders) { + mutableLoaders = [NSMutableArray array]; + } + [mutableLoaders addObject:loader]; + self.loaders = [mutableLoaders copy]; + UNLOCK(self.loadersLock); } - (void)removeLoader:(id)loader { + if (![loader conformsToProtocol:@protocol(SDWebImageLoader)]) { + return; + } LOCK(self.loadersLock); - [self.mutableLoaders removeObject:loader]; - UNLOCK(self.loadersLock); -} - -- (NSArray> *)loaders { - NSArray> *sortedLoaders; - LOCK(self.loadersLock); - sortedLoaders = [[[self.mutableLoaders copy] reverseObjectEnumerator] allObjects]; - UNLOCK(self.loadersLock); - return sortedLoaders; -} - -- (void)setLoaders:(NSArray> *)loaders { - LOCK(self.loadersLock); - self.mutableLoaders = [loaders mutableCopy]; + NSMutableArray> *mutableLoaders = [self.loaders mutableCopy]; + [mutableLoaders removeObject:loader]; + self.loaders = [mutableLoaders copy]; UNLOCK(self.loadersLock); } #pragma mark - SDWebImageLoader - (BOOL)canLoadWithURL:(nullable NSURL *)url { - for (id loader in self.loaders) { + LOCK(self.loadersLock); + NSArray> *loaders = self.loaders; + UNLOCK(self.loadersLock); + for (id loader in loaders.reverseObjectEnumerator) { if ([loader canLoadWithURL:url]) { return YES; } @@ -85,11 +84,12 @@ if (!url) { return nil; } - for (id loader in self.loaders) { + LOCK(self.loadersLock); + NSArray> *loaders = self.loaders; + UNLOCK(self.loadersLock); + for (id loader in loaders.reverseObjectEnumerator) { if ([loader respondsToSelector:@selector(loadImageWithURL:options:context:progress:completed:)]) { - if ([loader canLoadWithURL:url]) { - return [loader loadImageWithURL:url options:options context:context progress:progressBlock completed:completedBlock]; - } + return [loader loadImageWithURL:url options:options context:context progress:progressBlock completed:completedBlock]; } } return nil; diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 4fc599f8..5fafa45f 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -15,6 +15,8 @@ 321259EE1F39E4110096FE0E /* TestImageAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */; }; 3226ECBB20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */; }; 3226ECBC20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */; }; + 323B8E1F20862322008952BE /* SDWebImageTestLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 323B8E1E20862322008952BE /* SDWebImageTestLoader.m */; }; + 323B8E2020862322008952BE /* SDWebImageTestLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 323B8E1E20862322008952BE /* SDWebImageTestLoader.m */; }; 3254C32020641077008D1022 /* SDWebImageTransformerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */; }; 3254C32120641077008D1022 /* SDWebImageTransformerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */; }; 3264FF2F205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */; }; @@ -70,6 +72,8 @@ 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageAnimated.webp; sourceTree = ""; }; 3226ECB920754F7700FAFACF /* SDWebImageTestDownloadOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestDownloadOperation.h; sourceTree = ""; }; 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestDownloadOperation.m; sourceTree = ""; }; + 323B8E1D20862322008952BE /* SDWebImageTestLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestLoader.h; sourceTree = ""; }; + 323B8E1E20862322008952BE /* SDWebImageTestLoader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestLoader.m; sourceTree = ""; }; 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransformerTests.m; sourceTree = ""; }; 3264FF2D205D42CB00F6BD48 /* SDWebImageTestTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestTransformer.h; sourceTree = ""; }; 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestTransformer.m; sourceTree = ""; }; @@ -223,6 +227,8 @@ 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */, 3264FF2D205D42CB00F6BD48 /* SDWebImageTestTransformer.h */, 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */, + 323B8E1D20862322008952BE /* SDWebImageTestLoader.h */, + 323B8E1E20862322008952BE /* SDWebImageTestLoader.m */, ); path = Tests; sourceTree = ""; @@ -470,6 +476,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 323B8E2020862322008952BE /* SDWebImageTestLoader.m in Sources */, 32B99EAC203B36650017FD66 /* SDWebImageDownloaderTests.m in Sources */, 3254C32120641077008D1022 /* SDWebImageTransformerTests.m in Sources */, 328BB6DE20825E9800760D6C /* SDWebImageTestCache.m in Sources */, @@ -492,6 +499,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 323B8E1F20862322008952BE /* SDWebImageTestLoader.m in Sources */, 32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */, 3226ECBB20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */, 3254C32020641077008D1022 /* SDWebImageTransformerTests.m in Sources */, diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index c47550dc..2a2d568e 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -11,8 +11,10 @@ #import #import #import +#import #import "SDWebImageTestDownloadOperation.h" #import "SDWebImageTestDecoder.h" +#import "SDWebImageTestLoader.h" /** * Category for SDWebImageDownloader so we can access the operationClass @@ -414,4 +416,34 @@ [self waitForExpectationsWithCommonTimeout]; } +#pragma mark - SDWebImageLoader +- (void)test30CustomImageLoaderWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Custom image not works"]; + SDWebImageTestLoader *loader = [[SDWebImageTestLoader alloc] init]; + NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; + [loader loadImageWithURL:imageURL options:0 context:nil progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { + expect(targetURL).notTo.beNil(); + } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + expect(error).to.beNil(); + expect(image).notTo.beNil(); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithCommonTimeout]; +} + +- (void)test31ThatLoadersManagerWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Loaders manager not works"]; + NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; + [[SDWebImageLoadersManager sharedManager] loadImageWithURL:imageURL options:0 context:nil progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { + expect(targetURL).notTo.beNil(); + } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + expect(error).to.beNil(); + expect(image).notTo.beNil(); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithCommonTimeout]; +} + @end diff --git a/Tests/Tests/SDWebImageTestLoader.h b/Tests/Tests/SDWebImageTestLoader.h new file mode 100644 index 00000000..10250240 --- /dev/null +++ b/Tests/Tests/SDWebImageTestLoader.h @@ -0,0 +1,16 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Matt Galloway + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import + +// A really naive implementation of custom image loader using `NSURLSession` +@interface SDWebImageTestLoader : NSObject + +@end diff --git a/Tests/Tests/SDWebImageTestLoader.m b/Tests/Tests/SDWebImageTestLoader.m new file mode 100644 index 00000000..65165d73 --- /dev/null +++ b/Tests/Tests/SDWebImageTestLoader.m @@ -0,0 +1,53 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Matt Galloway + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageTestLoader.h" +#import + +@interface NSURLSessionTask (SDWebImageOperation) + +@end + +@implementation SDWebImageTestLoader + +- (BOOL)canLoadWithURL:(NSURL *)url { + return YES; +} + +- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDWebImageLoaderProgressBlock)progressBlock completed:(SDWebImageLoaderCompletedBlock)completedBlock { + NSURLRequest *request = [NSURLRequest requestWithURL:url]; + + NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + if (data) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + UIImage *image = SDWebImageLoaderDecodeImageData(data, url, options, context); + if (completedBlock) { + completedBlock(image, data, nil, YES); + } + }); + } else { + if (completedBlock) { + completedBlock(nil, nil, error, YES); + } + } + }]; + [self.KVOController observe:task keyPath:NSStringFromSelector(@selector(countOfBytesReceived)) options:NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionary * _Nonnull change) { + NSURLSessionTask *sessionTask = object; + NSInteger receivedSize = sessionTask.countOfBytesReceived; + NSInteger expectedSize = sessionTask.countOfBytesExpectedToReceive; + if (progressBlock) { + progressBlock(receivedSize, expectedSize, url); + } + }]; + [task resume]; + + return task; +} + +@end From 7cf58ad7c5f3b112c794dc919507373de4e005d2 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 18 Apr 2018 21:14:34 +0800 Subject: [PATCH 151/361] Renaming the NSImage category naming to `NSImage+Compatibility`, because it's only used for Cross-platform compatibility code. `Additions` is too wide --- SDWebImage.xcodeproj/project.pbxproj | 36 +++++++++---------- ...ge+Additions.h => NSImage+Compatibility.h} | 2 +- ...ge+Additions.m => NSImage+Compatibility.m} | 4 +-- SDWebImage/SDAnimatedImage.m | 2 +- SDWebImage/SDAnimatedImageView.m | 2 +- SDWebImage/SDImageCache.m | 2 +- SDWebImage/SDWebImageAPNGCoder.m | 2 +- SDWebImage/SDWebImageCoderHelper.m | 2 +- SDWebImage/SDWebImageCodersManager.m | 2 +- SDWebImage/SDWebImageDefine.m | 2 +- SDWebImage/SDWebImageDownloaderOperation.m | 2 +- SDWebImage/SDWebImageGIFCoder.m | 2 +- SDWebImage/SDWebImageImageIOCoder.m | 2 +- SDWebImage/SDWebImageManager.m | 2 +- SDWebImage/SDWebImageWebPCoder.m | 2 +- SDWebImage/UIImage+Transform.m | 2 +- SDWebImage/UIImage+WebCache.m | 2 +- Tests/Tests/SDWebImageDecoderTests.m | 2 +- WebImage/SDWebImage.h | 2 +- 19 files changed, 37 insertions(+), 37 deletions(-) rename SDWebImage/{NSImage+Additions.h => NSImage+Compatibility.h} (98%) rename SDWebImage/{NSImage+Additions.m => NSImage+Compatibility.m} (97%) diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 11e46035..82cb03d5 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -113,11 +113,11 @@ 321E60C71F38E91700405457 /* UIImage+ForceDecode.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */; }; 321E60C81F38E91700405457 /* UIImage+ForceDecode.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */; }; 321E60C91F38E91700405457 /* UIImage+ForceDecode.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */; }; - 3237F9E820161AE000A88143 /* NSImage+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */; }; - 3237F9E920161AE000A88143 /* NSImage+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */; }; - 3237F9EA20161AE000A88143 /* NSImage+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */; }; - 3237F9EB20161AE000A88143 /* NSImage+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */; }; - 3237F9EC20161AE000A88143 /* NSImage+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */; }; + 3237F9E820161AE000A88143 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; + 3237F9E920161AE000A88143 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; + 3237F9EA20161AE000A88143 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; + 3237F9EB20161AE000A88143 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; + 3237F9EC20161AE000A88143 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; 323F8B3E1F38EF770092B609 /* alpha_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B131F38EF770092B609 /* alpha_enc.c */; }; 323F8B3F1F38EF770092B609 /* alpha_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B131F38EF770092B609 /* alpha_enc.c */; }; 323F8B401F38EF770092B609 /* alpha_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 323F8B131F38EF770092B609 /* alpha_enc.c */; }; @@ -718,8 +718,8 @@ 4397D2EA1D0DDD8C00BB2784 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2EB1D0DDD8C00BB2784 /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2ED1D0DDD8C00BB2784 /* mux_types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC91998E60B007367ED /* mux_types.h */; }; - 4397D2F61D0DE2DF00BB2784 /* NSImage+Additions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4397D2F41D0DE2DF00BB2784 /* NSImage+Additions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2F71D0DE2DF00BB2784 /* NSImage+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */; }; + 4397D2F61D0DE2DF00BB2784 /* NSImage+Compatibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 4397D2F41D0DE2DF00BB2784 /* NSImage+Compatibility.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4397D2F71D0DE2DF00BB2784 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; 4397D2F81D0DF44200BB2784 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2F91D0DF44A00BB2784 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */; }; 43A62A1B1D0E0A800089D7DD /* decode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC41998E60B007367ED /* decode.h */; }; @@ -1611,8 +1611,8 @@ 4369C2751D9807EC007E863A /* UIView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+WebCache.h"; path = "SDWebImage/UIView+WebCache.h"; sourceTree = ""; }; 4369C2761D9807EC007E863A /* UIView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIView+WebCache.m"; path = "SDWebImage/UIView+WebCache.m"; sourceTree = ""; }; 4397D2F21D0DDD8C00BB2784 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 4397D2F41D0DE2DF00BB2784 /* NSImage+Additions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImage+Additions.h"; sourceTree = ""; }; - 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSImage+Additions.m"; sourceTree = ""; }; + 4397D2F41D0DE2DF00BB2784 /* NSImage+Compatibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImage+Compatibility.h"; sourceTree = ""; }; + 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSImage+Compatibility.m"; sourceTree = ""; }; 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageCacheConfig.h; sourceTree = ""; }; 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageCacheConfig.m; sourceTree = ""; }; 43C892981D9D6DD70022038D /* anim_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = anim_decode.c; sourceTree = ""; }; @@ -2099,8 +2099,8 @@ 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */, 32F7C07D2030719600873181 /* UIImage+Transform.h */, 32F7C07C2030719600873181 /* UIImage+Transform.m */, - 4397D2F41D0DE2DF00BB2784 /* NSImage+Additions.h */, - 4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */, + 4397D2F41D0DE2DF00BB2784 /* NSImage+Compatibility.h */, + 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */, AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */, AB615302192DA24600A2D8E9 /* UIView+WebCacheOperation.m */, ); @@ -2691,7 +2691,7 @@ 80377E661F2F66A800F89830 /* neon.h in Headers */, 4397D2DB1D0DDD8C00BB2784 /* UIImage+MultiFormat.h in Headers */, 4397D2DC1D0DDD8C00BB2784 /* SDWebImageOperation.h in Headers */, - 4397D2F61D0DE2DF00BB2784 /* NSImage+Additions.h in Headers */, + 4397D2F61D0DE2DF00BB2784 /* NSImage+Compatibility.h in Headers */, 4397D2E11D0DDD8C00BB2784 /* SDWebImageDownloader.h in Headers */, 323F8BFB1F38EF770092B609 /* animi.h in Headers */, 4397D2E31D0DDD8C00BB2784 /* MKAnnotationView+WebCache.h in Headers */, @@ -3178,7 +3178,7 @@ 80377C4E1F2F666300F89830 /* filters_utils.c in Sources */, 321E60B91F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 80377DEB1F2F66A700F89830 /* yuv.c in Sources */, - 3237F9E920161AE000A88143 /* NSImage+Additions.m in Sources */, + 3237F9E920161AE000A88143 /* NSImage+Compatibility.m in Sources */, 32C0FDEA2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 32F21B5A20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 00733A551BC4880000A5A117 /* SDWebImageDownloader.m in Sources */, @@ -3406,7 +3406,7 @@ 32C0FDE82013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 4314D1401D0E0E3B004B36C9 /* UIImageView+WebCache.m in Sources */, 43A9186C1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, - 3237F9EC20161AE000A88143 /* NSImage+Additions.m in Sources */, + 3237F9EC20161AE000A88143 /* NSImage+Compatibility.m in Sources */, 4314D1411D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.m in Sources */, 80377D561F2F66A700F89830 /* rescaler_neon.c in Sources */, 32B9B53E206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, @@ -3570,7 +3570,7 @@ 32C0FDEB2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 80377DEE1F2F66A800F89830 /* alpha_processing_neon.c in Sources */, 43C892A41D9D6DDD0022038D /* demux.c in Sources */, - 3237F9EA20161AE000A88143 /* NSImage+Additions.m in Sources */, + 3237F9EA20161AE000A88143 /* NSImage+Compatibility.m in Sources */, 431BB6B61D06D2C1006A3455 /* UIImage+WebP.m in Sources */, 80377E251F2F66A800F89830 /* rescaler_neon.c in Sources */, 32B9B541206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, @@ -3637,7 +3637,7 @@ 321E60911F38E8C800405457 /* SDWebImageCoder.m in Sources */, 80377C8A1F2F666400F89830 /* quant_levels_utils.c in Sources */, 4397D27F1D0DDD8C00BB2784 /* UIImage+WebP.m in Sources */, - 4397D2F71D0DE2DF00BB2784 /* NSImage+Additions.m in Sources */, + 4397D2F71D0DE2DF00BB2784 /* NSImage+Compatibility.m in Sources */, 80377E751F2F66A800F89830 /* yuv.c in Sources */, 43C892A01D9D6DDA0022038D /* anim_decode.c in Sources */, 80377E4A1F2F66A800F89830 /* enc_mips_dsp_r2.c in Sources */, @@ -3840,7 +3840,7 @@ 80377DA61F2F66A700F89830 /* yuv.c in Sources */, 321E60B81F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 43CE757A1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, - 3237F9E820161AE000A88143 /* NSImage+Additions.m in Sources */, + 3237F9E820161AE000A88143 /* NSImage+Compatibility.m in Sources */, 32C0FDE92013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 32F21B5920788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 80377D811F2F66A700F89830 /* enc.c in Sources */, @@ -4008,7 +4008,7 @@ 321E60B61F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 43CE75791CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, 80377CF71F2F66A100F89830 /* enc.c in Sources */, - 3237F9EB20161AE000A88143 /* NSImage+Additions.m in Sources */, + 3237F9EB20161AE000A88143 /* NSImage+Compatibility.m in Sources */, 32C0FDE72013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 32F21B5720788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 80377E871F2F66D000F89830 /* alpha_dec.c in Sources */, diff --git a/SDWebImage/NSImage+Additions.h b/SDWebImage/NSImage+Compatibility.h similarity index 98% rename from SDWebImage/NSImage+Additions.h rename to SDWebImage/NSImage+Compatibility.h index 6ae7e4cf..d41c1db8 100644 --- a/SDWebImage/NSImage+Additions.h +++ b/SDWebImage/NSImage+Compatibility.h @@ -12,7 +12,7 @@ #if SD_MAC -@interface NSImage (Additions) +@interface NSImage (Compatibility) /** The underlying Core Graphics image object. This will actually use `CGImageForProposedRect` with the image size. diff --git a/SDWebImage/NSImage+Additions.m b/SDWebImage/NSImage+Compatibility.m similarity index 97% rename from SDWebImage/NSImage+Additions.m rename to SDWebImage/NSImage+Compatibility.m index 7cfb99ad..df6f7faf 100644 --- a/SDWebImage/NSImage+Additions.m +++ b/SDWebImage/NSImage+Compatibility.m @@ -6,13 +6,13 @@ * file that was distributed with this source code. */ -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #if SD_MAC #import "SDWebImageCoderHelper.h" -@implementation NSImage (Additions) +@implementation NSImage (Compatibility) - (CGImageRef)CGImage { NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index c54dc112..1b5da1c0 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -7,7 +7,7 @@ */ #import "SDAnimatedImage.h" -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" #import "SDWebImageCoder.h" #import "SDWebImageCodersManager.h" diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index 386efe88..af4a4e6c 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -11,7 +11,7 @@ #if SD_UIKIT || SD_MAC #import "UIImage+WebCache.h" -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #import #import diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index dd92e8e4..927d4b7c 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -9,7 +9,7 @@ #import "SDImageCache.h" #import "SDMemoryCache.h" #import "SDDiskCache.h" -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" #import "SDWebImageCodersManager.h" #import "SDWebImageTransformer.h" diff --git a/SDWebImage/SDWebImageAPNGCoder.m b/SDWebImage/SDWebImageAPNGCoder.m index c6b694c3..6d5c03c9 100644 --- a/SDWebImage/SDWebImageAPNGCoder.m +++ b/SDWebImage/SDWebImageAPNGCoder.m @@ -10,7 +10,7 @@ #import #import "NSData+ImageContentType.h" #import "UIImage+WebCache.h" -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #import "SDWebImageCoderHelper.h" #import "SDAnimatedImageRep.h" diff --git a/SDWebImage/SDWebImageCoderHelper.m b/SDWebImage/SDWebImageCoderHelper.m index 07f820ce..348124aa 100644 --- a/SDWebImage/SDWebImageCoderHelper.m +++ b/SDWebImage/SDWebImageCoderHelper.m @@ -8,7 +8,7 @@ #import "SDWebImageCoderHelper.h" #import "SDWebImageFrame.h" -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #import "NSData+ImageContentType.h" #import "SDAnimatedImageRep.h" #import "UIImage+ForceDecode.h" diff --git a/SDWebImage/SDWebImageCodersManager.m b/SDWebImage/SDWebImageCodersManager.m index 67e2e2c8..8f33b816 100644 --- a/SDWebImage/SDWebImageCodersManager.m +++ b/SDWebImage/SDWebImageCodersManager.m @@ -13,7 +13,7 @@ #ifdef SD_WEBP #import "SDWebImageWebPCoder.h" #endif -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" #import "SDWebImageDefine.h" diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m index 6b843ac0..0f386021 100644 --- a/SDWebImage/SDWebImageDefine.m +++ b/SDWebImage/SDWebImageDefine.m @@ -8,7 +8,7 @@ #import "SDWebImageDefine.h" #import "UIImage+WebCache.h" -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #pragma mark - Image scale diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 511cf8e2..bab10f85 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -8,7 +8,7 @@ #import "SDWebImageDownloaderOperation.h" #import "SDWebImageManager.h" -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" #import "SDWebImageCodersManager.h" #import "SDWebImageCoderHelper.h" diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index c44af183..fb7523e9 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -7,7 +7,7 @@ */ #import "SDWebImageGIFCoder.h" -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" #import #import "NSData+ImageContentType.h" diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index cc7feda5..422aec00 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -8,7 +8,7 @@ #import "SDWebImageImageIOCoder.h" #import "SDWebImageCoderHelper.h" -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #import #import "NSData+ImageContentType.h" diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 84c72340..fed2eae4 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -8,7 +8,7 @@ #import "SDWebImageManager.h" #import "SDImageCache.h" -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" #import "SDAnimatedImage.h" #import "SDWebImageError.h" diff --git a/SDWebImage/SDWebImageWebPCoder.m b/SDWebImage/SDWebImageWebPCoder.m index 89ea48d1..a0ec4792 100644 --- a/SDWebImage/SDWebImageWebPCoder.m +++ b/SDWebImage/SDWebImageWebPCoder.m @@ -10,7 +10,7 @@ #import "SDWebImageWebPCoder.h" #import "SDWebImageCoderHelper.h" -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" #if __has_include() && __has_include() && __has_include() && __has_include() #import diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 1ba361eb..00206685 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -7,7 +7,7 @@ */ #import "UIImage+Transform.h" -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #import #if SD_UIKIT || SD_MAC #import diff --git a/SDWebImage/UIImage+WebCache.m b/SDWebImage/UIImage+WebCache.m index ffdfe35f..0ec283b1 100644 --- a/SDWebImage/UIImage+WebCache.m +++ b/SDWebImage/UIImage+WebCache.m @@ -7,7 +7,7 @@ */ #import "UIImage+WebCache.h" -#import "NSImage+Additions.h" +#import "NSImage+Compatibility.h" #import "objc/runtime.h" #if SD_UIKIT diff --git a/Tests/Tests/SDWebImageDecoderTests.m b/Tests/Tests/SDWebImageDecoderTests.m index 94c19643..71966dae 100644 --- a/Tests/Tests/SDWebImageDecoderTests.m +++ b/Tests/Tests/SDWebImageDecoderTests.m @@ -15,7 +15,7 @@ #import #import #if SD_MAC -#import +#import #endif #import diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index a98f0e97..f5b8e7ca 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -71,7 +71,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #if SD_MAC - #import + #import #import #import #endif From f81480189dd5a196aaf2ab281ea0a43a37c32c56 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 19 Apr 2018 16:22:47 +0800 Subject: [PATCH 152/361] Add modulemap files for SDWebImage to support modular framework, move the WebP & GIF into subdirectory to make Podspec works --- .../SDWebImage Demo.xcodeproj/project.pbxproj | 2 + SDWebImage.podspec | 12 +- SDWebImage.xcodeproj/project.pbxproj | 174 ++++++++++-------- .../{ => MapKit}/MKAnnotationView+WebCache.h | 0 .../{ => MapKit}/MKAnnotationView+WebCache.m | 0 SDWebImage/{ => WebP}/SDWebImageWebPCoder.h | 0 SDWebImage/{ => WebP}/SDWebImageWebPCoder.m | 0 SDWebImage/{ => WebP}/UIImage+WebP.h | 0 SDWebImage/{ => WebP}/UIImage+WebP.m | 0 WebImage/SDWebImage.h | 46 ++--- WebImage/SDWebImage.modulemap | 6 + 11 files changed, 136 insertions(+), 104 deletions(-) rename SDWebImage/{ => MapKit}/MKAnnotationView+WebCache.h (100%) rename SDWebImage/{ => MapKit}/MKAnnotationView+WebCache.m (100%) rename SDWebImage/{ => WebP}/SDWebImageWebPCoder.h (100%) rename SDWebImage/{ => WebP}/SDWebImageWebPCoder.m (100%) rename SDWebImage/{ => WebP}/UIImage+WebP.h (100%) rename SDWebImage/{ => WebP}/UIImage+WebP.m (100%) create mode 100644 WebImage/SDWebImage.modulemap diff --git a/Examples/SDWebImage Demo.xcodeproj/project.pbxproj b/Examples/SDWebImage Demo.xcodeproj/project.pbxproj index 3b676116..70bc067c 100644 --- a/Examples/SDWebImage Demo.xcodeproj/project.pbxproj +++ b/Examples/SDWebImage Demo.xcodeproj/project.pbxproj @@ -1284,6 +1284,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -1312,6 +1313,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", diff --git a/SDWebImage.podspec b/SDWebImage.podspec index 8f3dd0b8..470015bd 100644 --- a/SDWebImage.podspec +++ b/SDWebImage.podspec @@ -23,20 +23,20 @@ Pod::Spec.new do |s| s.requires_arc = true s.framework = 'ImageIO' + s.module_map = 'WebImage/SDWebImage.modulemap' s.default_subspec = 'Core' s.subspec 'Core' do |core| - core.source_files = 'SDWebImage/{NS,SD,UI}*.{h,m}' - core.exclude_files = 'SDWebImage/UIImage+WebP.{h,m}', 'SDWebImage/SDWebImageWebPCoder.{h,m}' - core.tvos.exclude_files = 'SDWebImage/MKAnnotationView+WebCache.*' + core.source_files = 'SDWebImage/*.{h,m}', 'WebImage/SDWebImage.h' + core.exclude_files = 'SDWebImage/MapKit/*.{h,m}', 'SDWebImage/WebP/*.{h,m}', 'SDWebImage/FLAnimatedImage/*.{h,m}' end s.subspec 'MapKit' do |mk| mk.osx.deployment_target = '10.10' mk.ios.deployment_target = '8.0' - mk.tvos.deployment_target = '9.0' - mk.source_files = 'SDWebImage/MKAnnotationView+WebCache.*' + mk.tvos.deployment_target = '9.2' + mk.source_files = 'SDWebImage/MapKit/*.{h,m}' mk.framework = 'MapKit' mk.dependency 'SDWebImage/Core' end @@ -52,7 +52,7 @@ Pod::Spec.new do |s| end s.subspec 'WebP' do |webp| - webp.source_files = 'SDWebImage/UIImage+WebP.{h,m}', 'SDWebImage/SDWebImageWebPCoder.{h,m}' + webp.source_files = 'SDWebImage/WebP/*.{h,m}' webp.xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SD_WEBP=1', 'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/libwebp/src' diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 09f892e7..ec3e6d5b 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -17,7 +17,6 @@ 00733A5C1BC4880000A5A117 /* UIButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D94148C56230056699D /* UIButton+WebCache.m */; }; 00733A5D1BC4880000A5A117 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = A18A6CC6172DC28500419892 /* UIImage+GIF.m */; }; 00733A5E1BC4880000A5A117 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */; }; - 00733A5F1BC4880000A5A117 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB921762547C00698166 /* UIImage+WebP.m */; }; 00733A601BC4880000A5A117 /* UIImageView+HighlightedWebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */; }; 00733A611BC4880000A5A117 /* UIImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D96148C56230056699D /* UIImageView+WebCache.m */; }; 00733A621BC4880000A5A117 /* UIView+WebCacheOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AB615302192DA24600A2D8E9 /* UIView+WebCacheOperation.m */; }; @@ -32,7 +31,6 @@ 00733A6C1BC4880E00A5A117 /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D93148C56230056699D /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 00733A6D1BC4880E00A5A117 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; 00733A6E1BC4880E00A5A117 /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 00733A6F1BC4880E00A5A117 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB911762547C00698166 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; 00733A701BC4880E00A5A117 /* UIImageView+HighlightedWebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = ABBE71A518C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 00733A711BC4880E00A5A117 /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D95148C56230056699D /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 00733A721BC4880E00A5A117 /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -113,18 +111,6 @@ 321E60AB1F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */; }; 321E60AC1F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */; }; 321E60AD1F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */; }; - 321E60B01F38E90100405457 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60AE1F38E90100405457 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60B11F38E90100405457 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60AE1F38E90100405457 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60B21F38E90100405457 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60AE1F38E90100405457 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60B31F38E90100405457 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60AE1F38E90100405457 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60B41F38E90100405457 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60AE1F38E90100405457 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60B51F38E90100405457 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60AE1F38E90100405457 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60B61F38E90100405457 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60AF1F38E90100405457 /* SDWebImageWebPCoder.m */; }; - 321E60B71F38E90100405457 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60AF1F38E90100405457 /* SDWebImageWebPCoder.m */; }; - 321E60B81F38E90100405457 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60AF1F38E90100405457 /* SDWebImageWebPCoder.m */; }; - 321E60B91F38E90100405457 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60AF1F38E90100405457 /* SDWebImageWebPCoder.m */; }; - 321E60BA1F38E90100405457 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60AF1F38E90100405457 /* SDWebImageWebPCoder.m */; }; - 321E60BB1F38E90100405457 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60AF1F38E90100405457 /* SDWebImageWebPCoder.m */; }; 321E60BE1F38E91700405457 /* UIImage+ForceDecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321E60BF1F38E91700405457 /* UIImage+ForceDecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321E60C01F38E91700405457 /* UIImage+ForceDecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -597,9 +583,42 @@ 32F7C0872030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32F7C0882030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32F7C0892030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE87C2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */; }; + 32FDE87D2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */; }; + 32FDE87E2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */; }; + 32FDE87F2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */; }; + 32FDE8802088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE8812088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE8822088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE8832088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE88920888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; + 32FDE88A20888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; + 32FDE88B20888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; + 32FDE88C20888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; + 32FDE88D20888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; + 32FDE88E20888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; + 32FDE88F20888726008D7530 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89020888726008D7530 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89120888726008D7530 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89220888726008D7530 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89320888726008D7530 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89420888726008D7530 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89520888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89620888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89720888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89820888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89920888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89A20888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89B20888726008D7530 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */; }; + 32FDE89C20888726008D7530 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */; }; + 32FDE89D20888726008D7530 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */; }; + 32FDE89E20888726008D7530 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */; }; + 32FDE89F20888726008D7530 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */; }; + 32FDE8A020888726008D7530 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */; }; + 32FDE8A220888789008D7530 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE8A320888789008D7530 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D1231D0E0E3B004B36C9 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D86148C56230056699D /* SDImageCache.m */; }; 4314D1311D0E0E3B004B36C9 /* SDWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8C148C56230056699D /* SDWebImageDownloader.m */; }; - 4314D1341D0E0E3B004B36C9 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB921762547C00698166 /* UIImage+WebP.m */; }; 4314D1361D0E0E3B004B36C9 /* SDWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8F148C56230056699D /* SDWebImageManager.m */; }; 4314D1371D0E0E3B004B36C9 /* SDWebImagePrefetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D92148C56230056699D /* SDWebImagePrefetcher.m */; }; 4314D13B1D0E0E3B004B36C9 /* UIButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D94148C56230056699D /* UIButton+WebCache.m */; }; @@ -625,7 +644,6 @@ 4314D1761D0E0E3B004B36C9 /* decode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC41998E60B007367ED /* decode.h */; }; 4314D1781D0E0E3B004B36C9 /* SDWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8B148C56230056699D /* SDWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D1791D0E0E3B004B36C9 /* SDWebImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8E148C56230056699D /* SDWebImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4314D17C1D0E0E3B004B36C9 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB911762547C00698166 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D17D1D0E0E3B004B36C9 /* SDWebImagePrefetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D91148C56230056699D /* SDWebImagePrefetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D17F1D0E0E3B004B36C9 /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D93148C56230056699D /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D1811D0E0E3B004B36C9 /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D95148C56230056699D /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -665,13 +683,11 @@ 431BB6AA1D06D2C1006A3455 /* SDWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8F148C56230056699D /* SDWebImageManager.m */; }; 431BB6AC1D06D2C1006A3455 /* SDWebImageCompat.m in Sources */ = {isa = PBXBuildFile; fileRef = 5340674F167780C40042B59E /* SDWebImageCompat.m */; }; 431BB6B11D06D2C1006A3455 /* UIView+WebCacheOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AB615302192DA24600A2D8E9 /* UIView+WebCacheOperation.m */; }; - 431BB6B61D06D2C1006A3455 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB921762547C00698166 /* UIImage+WebP.m */; }; 431BB6B91D06D2C1006A3455 /* UIButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D94148C56230056699D /* UIButton+WebCache.m */; }; 431BB6BD1D06D2C1006A3455 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = A18A6CC6172DC28500419892 /* UIImage+GIF.m */; }; 431BB6C01D06D2C1006A3455 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D86148C56230056699D /* SDImageCache.m */; }; 431BB6C41D06D2C1006A3455 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */; }; 431BB6C71D06D2C1006A3455 /* UIImageView+HighlightedWebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */; }; - 431BB6D71D06D2C1006A3455 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB911762547C00698166 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; 431BB6D91D06D2C1006A3455 /* SDWebImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8E148C56230056699D /* SDWebImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 431BB6DC1D06D2C1006A3455 /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D93148C56230056699D /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 431BB6E11D06D2C1006A3455 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -699,15 +715,9 @@ 4369C2811D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; }; 4369C2821D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; }; 4369C2831D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; }; - 438096721CDFC08200DC626B /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 438096731CDFC08F00DC626B /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */; }; - 438096741CDFC09C00DC626B /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB911762547C00698166 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 438096751CDFC0A100DC626B /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB921762547C00698166 /* UIImage+WebP.m */; }; 4397D27E1D0DDD8C00BB2784 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = A18A6CC6172DC28500419892 /* UIImage+GIF.m */; }; - 4397D27F1D0DDD8C00BB2784 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB921762547C00698166 /* UIImage+WebP.m */; }; 4397D28C1D0DDD8C00BB2784 /* UIImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D96148C56230056699D /* UIImageView+WebCache.m */; }; 4397D28F1D0DDD8C00BB2784 /* SDWebImageDownloaderOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 530E49E416460AE2002868E7 /* SDWebImageDownloaderOperation.m */; }; - 4397D2911D0DDD8C00BB2784 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */; }; 4397D2921D0DDD8C00BB2784 /* SDWebImagePrefetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D92148C56230056699D /* SDWebImagePrefetcher.m */; }; 4397D2961D0DDD8C00BB2784 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */; }; 4397D29B1D0DDD8C00BB2784 /* SDWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8C148C56230056699D /* SDWebImageDownloader.m */; }; @@ -736,16 +746,12 @@ 4397D2DB1D0DDD8C00BB2784 /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2DC1D0DDD8C00BB2784 /* SDWebImageOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 530E49E71646388E002868E7 /* SDWebImageOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2E11D0DDD8C00BB2784 /* SDWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8B148C56230056699D /* SDWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2E31D0DDD8C00BB2784 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2E61D0DDD8C00BB2784 /* encode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC61998E60B007367ED /* encode.h */; }; - 4397D2E91D0DDD8C00BB2784 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB911762547C00698166 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2EA1D0DDD8C00BB2784 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2EB1D0DDD8C00BB2784 /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2ED1D0DDD8C00BB2784 /* mux_types.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC91998E60B007367ED /* mux_types.h */; }; 4397D2F61D0DE2DF00BB2784 /* NSImage+Compatibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 4397D2F41D0DE2DF00BB2784 /* NSImage+Compatibility.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4397D2F71D0DE2DF00BB2784 /* NSImage+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */; }; - 4397D2F81D0DF44200BB2784 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4397D2F91D0DF44A00BB2784 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */; }; 43A62A1B1D0E0A800089D7DD /* decode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC41998E60B007367ED /* decode.h */; }; 43A62A1C1D0E0A800089D7DD /* demux.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC51998E60B007367ED /* demux.h */; }; 43A62A1D1D0E0A800089D7DD /* encode.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577CC61998E60B007367ED /* encode.h */; }; @@ -809,8 +815,6 @@ 4A2CAE221AB4BB7000B6BC39 /* SDWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8F148C56230056699D /* SDWebImageManager.m */; }; 4A2CAE251AB4BB7000B6BC39 /* SDWebImagePrefetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D91148C56230056699D /* SDWebImagePrefetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4A2CAE261AB4BB7000B6BC39 /* SDWebImagePrefetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D92148C56230056699D /* SDWebImagePrefetcher.m */; }; - 4A2CAE271AB4BB7500B6BC39 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4A2CAE281AB4BB7500B6BC39 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */; }; 4A2CAE291AB4BB7500B6BC39 /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4A2CAE2A1AB4BB7500B6BC39 /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */; }; 4A2CAE2B1AB4BB7500B6BC39 /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D93148C56230056699D /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -819,8 +823,6 @@ 4A2CAE2E1AB4BB7500B6BC39 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = A18A6CC6172DC28500419892 /* UIImage+GIF.m */; }; 4A2CAE2F1AB4BB7500B6BC39 /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4A2CAE301AB4BB7500B6BC39 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */; }; - 4A2CAE311AB4BB7500B6BC39 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB911762547C00698166 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4A2CAE321AB4BB7500B6BC39 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB921762547C00698166 /* UIImage+WebP.m */; }; 4A2CAE331AB4BB7500B6BC39 /* UIImageView+HighlightedWebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = ABBE71A518C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4A2CAE341AB4BB7500B6BC39 /* UIImageView+HighlightedWebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */; }; 4A2CAE351AB4BB7500B6BC39 /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D95148C56230056699D /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1555,8 +1557,6 @@ 321E60931F38E8ED00405457 /* SDWebImageImageIOCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageImageIOCoder.m; sourceTree = ""; }; 321E60A01F38E8F600405457 /* SDWebImageGIFCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageGIFCoder.h; sourceTree = ""; }; 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageGIFCoder.m; sourceTree = ""; }; - 321E60AE1F38E90100405457 /* SDWebImageWebPCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageWebPCoder.h; sourceTree = ""; }; - 321E60AF1F38E90100405457 /* SDWebImageWebPCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageWebPCoder.m; sourceTree = ""; }; 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+ForceDecode.h"; sourceTree = ""; }; 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+ForceDecode.m"; sourceTree = ""; }; 323F8B131F38EF770092B609 /* alpha_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alpha_enc.c; sourceTree = ""; }; @@ -1634,6 +1634,13 @@ 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransformer.m; sourceTree = ""; }; 32F7C07C2030719600873181 /* UIImage+Transform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Transform.m"; sourceTree = ""; }; 32F7C07D2030719600873181 /* UIImage+Transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Transform.h"; sourceTree = ""; }; + 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MKAnnotationView+WebCache.m"; sourceTree = ""; }; + 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MKAnnotationView+WebCache.h"; sourceTree = ""; }; + 32FDE88520888726008D7530 /* UIImage+WebP.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+WebP.m"; sourceTree = ""; }; + 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageWebPCoder.h; sourceTree = ""; }; + 32FDE88720888726008D7530 /* UIImage+WebP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+WebP.h"; sourceTree = ""; }; + 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageWebPCoder.m; sourceTree = ""; }; + 32FDE8A4208887A6008D7530 /* SDWebImage.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = SDWebImage.modulemap; sourceTree = ""; }; 4314D1991D0E0E3B004B36C9 /* libSDWebImage watchOS static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libSDWebImage watchOS static.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 431BB7031D06D2C1006A3455 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4369C2751D9807EC007E863A /* UIView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+WebCache.h"; path = "SDWebImage/UIView+WebCache.h"; sourceTree = ""; }; @@ -1658,8 +1665,6 @@ 530E49E416460AE2002868E7 /* SDWebImageDownloaderOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderOperation.m; sourceTree = ""; }; 530E49E71646388E002868E7 /* SDWebImageOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageOperation.h; sourceTree = ""; }; 5340674F167780C40042B59E /* SDWebImageCompat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCompat.m; sourceTree = ""; }; - 535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "MKAnnotationView+WebCache.h"; path = "SDWebImage/MKAnnotationView+WebCache.h"; sourceTree = SOURCE_ROOT; }; - 535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "MKAnnotationView+WebCache.m"; path = "SDWebImage/MKAnnotationView+WebCache.m"; sourceTree = SOURCE_ROOT; }; 53761325155AD0D5005750A4 /* libSDWebImage iOS static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libSDWebImage iOS static.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 53922D72148C55820056699D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 53922D85148C56230056699D /* SDImageCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDImageCache.h; path = SDWebImage/SDImageCache.h; sourceTree = SOURCE_ROOT; }; @@ -1677,8 +1682,6 @@ 53922D96148C56230056699D /* UIImageView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+WebCache.m"; path = "SDWebImage/UIImageView+WebCache.m"; sourceTree = SOURCE_ROOT; }; 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+MultiFormat.h"; sourceTree = ""; }; 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+MultiFormat.m"; sourceTree = ""; }; - 53EDFB911762547C00698166 /* UIImage+WebP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+WebP.h"; sourceTree = ""; }; - 53EDFB921762547C00698166 /* UIImage+WebP.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+WebP.m"; sourceTree = ""; }; 53FB893F14D35D1A0020B787 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 53FB894814D35E9E0020B787 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+ImageContentType.h"; sourceTree = ""; }; @@ -1874,8 +1877,6 @@ 321E60931F38E8ED00405457 /* SDWebImageImageIOCoder.m */, 321E60A01F38E8F600405457 /* SDWebImageGIFCoder.h */, 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */, - 321E60AE1F38E90100405457 /* SDWebImageWebPCoder.h */, - 321E60AF1F38E90100405457 /* SDWebImageWebPCoder.m */, 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */, 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */, 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */, @@ -1981,6 +1982,26 @@ name = Transformer; sourceTree = ""; }; + 32FDE8792088871B008D7530 /* MapKit */ = { + isa = PBXGroup; + children = ( + 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */, + 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */, + ); + path = MapKit; + sourceTree = ""; + }; + 32FDE88420888726008D7530 /* WebP */ = { + isa = PBXGroup; + children = ( + 32FDE88720888726008D7530 /* UIImage+WebP.h */, + 32FDE88520888726008D7530 /* UIImage+WebP.m */, + 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */, + 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */, + ); + path = WebP; + sourceTree = ""; + }; 4369C2851D9811BB007E863A /* WebCache Categories */ = { isa = PBXGroup; children = ( @@ -1988,8 +2009,6 @@ 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */, 321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */, 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */, - 535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */, - 535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */, 53922D93148C56230056699D /* UIButton+WebCache.h */, 53922D94148C56230056699D /* UIButton+WebCache.m */, ABBE71A518C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h */, @@ -2054,6 +2073,7 @@ isa = PBXGroup; children = ( 4A2CAE021AB4BB5400B6BC39 /* Info.plist */, + 32FDE8A4208887A6008D7530 /* SDWebImage.modulemap */, ); name = "Supporting Files"; sourceTree = ""; @@ -2107,6 +2127,8 @@ 53922DAC148C56DD0056699D /* Utils */, 53922DA9148C562D0056699D /* Categories */, 4369C2851D9811BB007E863A /* WebCache Categories */, + 32FDE8792088871B008D7530 /* MapKit */, + 32FDE88420888726008D7530 /* WebP */, 43CE75CD1CFE98B3006C64D0 /* FLAnimatedImage */, ); path = SDWebImage; @@ -2121,8 +2143,6 @@ A18A6CC6172DC28500419892 /* UIImage+GIF.m */, 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */, 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */, - 53EDFB911762547C00698166 /* UIImage+WebP.h */, - 53EDFB921762547C00698166 /* UIImage+WebP.m */, 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */, 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */, 32F7C07D2030719600873181 /* UIImage+Transform.h */, @@ -2379,7 +2399,6 @@ 328BB6AD2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 80377C4A1F2F666300F89830 /* bit_writer_utils.h in Headers */, 321B37902083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, - 4397D2F81D0DF44200BB2784 /* MKAnnotationView+WebCache.h in Headers */, 323F8BE71F38EF770092B609 /* vp8li_enc.h in Headers */, 329A185C1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 4369C27A1D9807EC007E863A /* UIView+WebCache.h in Headers */, @@ -2389,9 +2408,7 @@ 43A918671D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 327054D7206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, 431739571CDFC8B70008FEB9 /* encode.h in Headers */, - 00733A6F1BC4880E00A5A117 /* UIImage+WebP.h in Headers */, 323F8B711F38EF770092B609 /* delta_palettization_enc.h in Headers */, - 321E60B31F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 3290FA071FA478AF0047D20C /* SDWebImageFrame.h in Headers */, 324DF4B7200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 807A122B1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, @@ -2406,6 +2423,7 @@ 80377DDB1F2F66A700F89830 /* msa_macro.h in Headers */, 4317395B1CDFC8B70008FEB9 /* types.h in Headers */, 80377C531F2F666300F89830 /* huffman_utils.h in Headers */, + 32FDE8822088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, 43CE75D21CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */, 431739551CDFC8B70008FEB9 /* decode.h in Headers */, 00733A731BC4880E00A5A117 /* SDWebImage.h in Headers */, @@ -2414,6 +2432,7 @@ 00733A701BC4880E00A5A117 /* UIImageView+HighlightedWebCache.h in Headers */, 323F8BDB1F38EF770092B609 /* vp8i_enc.h in Headers */, 80377C461F2F666300F89830 /* bit_reader_inl_utils.h in Headers */, + 32FDE89220888726008D7530 /* SDWebImageWebPCoder.h in Headers */, 00733A671BC4880E00A5A117 /* SDImageCache.h in Headers */, 00733A711BC4880E00A5A117 /* UIImageView+WebCache.h in Headers */, 00733A631BC4880E00A5A117 /* SDWebImageCompat.h in Headers */, @@ -2444,6 +2463,7 @@ 80377EBA1F2F66D500F89830 /* common_dec.h in Headers */, 43CE757E1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, 3248476C201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, + 32FDE89820888726008D7530 /* UIImage+WebP.h in Headers */, 80377C5F1F2F666300F89830 /* utils.h in Headers */, 80377C5B1F2F666300F89830 /* rescaler_utils.h in Headers */, 32D122332080B2EB003685A3 /* SDImageCachesManager.h in Headers */, @@ -2472,7 +2492,6 @@ 80377D261F2F66A700F89830 /* common_sse2.h in Headers */, 3290FA051FA478AF0047D20C /* SDWebImageFrame.h in Headers */, 80377C1D1F2F666300F89830 /* huffman_encode_utils.h in Headers */, - 321E60B11F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 80377E9A1F2F66D400F89830 /* common_dec.h in Headers */, 32D1221F2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 327054D5206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, @@ -2483,6 +2502,7 @@ 80377EA61F2F66D400F89830 /* webpi_dec.h in Headers */, 807A12291F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, 32F7C0852030719600873181 /* UIImage+Transform.h in Headers */, + 32FDE89020888726008D7530 /* SDWebImageWebPCoder.h in Headers */, 80377C141F2F666300F89830 /* bit_reader_utils.h in Headers */, 328BB69D2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, 323F8C0F1F38EF770092B609 /* muxi.h in Headers */, @@ -2532,10 +2552,11 @@ 324DF4B5200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 80377C191F2F666300F89830 /* endian_inl_utils.h in Headers */, 321E60A31F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, - 4314D17C1D0E0E3B004B36C9 /* UIImage+WebP.h in Headers */, + 32FDE8A320888789008D7530 /* SDWebImage.h in Headers */, 32F21B5220788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 4369C2781D9807EC007E863A /* UIView+WebCache.h in Headers */, 80377D621F2F66A700F89830 /* yuv.h in Headers */, + 32FDE89620888726008D7530 /* UIImage+WebP.h in Headers */, 80377D341F2F66A700F89830 /* dsp.h in Headers */, 4314D17D1D0E0E3B004B36C9 /* SDWebImagePrefetcher.h in Headers */, 80377C181F2F666300F89830 /* color_cache_utils.h in Headers */, @@ -2569,7 +2590,6 @@ 328BB6A02081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, 323F8B721F38EF770092B609 /* delta_palettization_enc.h in Headers */, 32CF1C0B1FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, - 431BB6D71D06D2C1006A3455 /* UIImage+WebP.h in Headers */, 431BB6D91D06D2C1006A3455 /* SDWebImageManager.h in Headers */, 80377C691F2F666400F89830 /* filters_utils.h in Headers */, 80377EC81F2F66D500F89830 /* alphai_dec.h in Headers */, @@ -2577,6 +2597,7 @@ 321E608A1F38E8C800405457 /* SDWebImageCoder.h in Headers */, 32484767201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80377C601F2F666400F89830 /* bit_reader_inl_utils.h in Headers */, + 32FDE89920888726008D7530 /* UIImage+WebP.h in Headers */, 321B37852083290E00C0EA77 /* SDWebImageLoader.h in Headers */, 329A185D1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 431BB6DC1D06D2C1006A3455 /* UIButton+WebCache.h in Headers */, @@ -2621,6 +2642,7 @@ 32C0FDE52013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 80377ED61F2F66D500F89830 /* webpi_dec.h in Headers */, 323F8BE81F38EF770092B609 /* vp8li_enc.h in Headers */, + 32FDE89320888726008D7530 /* SDWebImageWebPCoder.h in Headers */, 323F8B8A1F38EF770092B609 /* histogram_enc.h in Headers */, 80377E1E1F2F66A800F89830 /* lossless.h in Headers */, 321E60981F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, @@ -2643,7 +2665,6 @@ 807A122C1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, 323F8BFA1F38EF770092B609 /* animi.h in Headers */, 431BB6F91D06D2C1006A3455 /* UIImage+GIF.h in Headers */, - 321E60B41F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 32F7C0732030114C00873181 /* SDWebImageTransformer.h in Headers */, 431BB6FA1D06D2C1006A3455 /* SDWebImageDownloader.h in Headers */, 3248476D201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, @@ -2697,6 +2718,7 @@ 4397D2CC1D0DDD8C00BB2784 /* mux.h in Headers */, 80377C911F2F666400F89830 /* thread_utils.h in Headers */, 320CAE1A2086F50500CFFC80 /* SDWebImageError.h in Headers */, + 32FDE8832088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, 4397D2D01D0DDD8C00BB2784 /* SDWebImageDownloaderOperation.h in Headers */, 4397D2D11D0DDD8C00BB2784 /* decode.h in Headers */, 80377E481F2F66A800F89830 /* dsp.h in Headers */, @@ -2705,6 +2727,7 @@ 329A185E1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 320224BB203979BA00E9F285 /* SDAnimatedImageRep.h in Headers */, 328BB6C62082581100760D6C /* SDDiskCache.h in Headers */, + 32FDE89420888726008D7530 /* SDWebImageWebPCoder.h in Headers */, 80377E761F2F66A800F89830 /* yuv.h in Headers */, 80377C7A1F2F666400F89830 /* bit_reader_inl_utils.h in Headers */, 80377E631F2F66A800F89830 /* lossless.h in Headers */, @@ -2734,8 +2757,8 @@ 4397D2F61D0DE2DF00BB2784 /* NSImage+Compatibility.h in Headers */, 4397D2E11D0DDD8C00BB2784 /* SDWebImageDownloader.h in Headers */, 323F8BFB1F38EF770092B609 /* animi.h in Headers */, - 4397D2E31D0DDD8C00BB2784 /* MKAnnotationView+WebCache.h in Headers */, 4397D2E61D0DDD8C00BB2784 /* encode.h in Headers */, + 32FDE89A20888726008D7530 /* UIImage+WebP.h in Headers */, 80377C7C1F2F666400F89830 /* bit_reader_utils.h in Headers */, 321E608B1F38E8C800405457 /* SDWebImageCoder.h in Headers */, 323F8B731F38EF770092B609 /* delta_palettization_enc.h in Headers */, @@ -2743,10 +2766,8 @@ 32D122352080B2EB003685A3 /* SDImageCachesManager.h in Headers */, 32484768201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80377E561F2F66A800F89830 /* lossless_common.h in Headers */, - 4397D2E91D0DDD8C00BB2784 /* UIImage+WebP.h in Headers */, 325312CD200F09910046BF1E /* SDWebImageTransition.h in Headers */, 4397D2EA1D0DDD8C00BB2784 /* UIImage+GIF.h in Headers */, - 321E60B51F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 4397D2EB1D0DDD8C00BB2784 /* NSData+ImageContentType.h in Headers */, 80377C851F2F666400F89830 /* huffman_encode_utils.h in Headers */, 321DB3612011D4D70015D2CB /* NSButton+WebCache.h in Headers */, @@ -2786,7 +2807,6 @@ 431739511CDFC8B70008FEB9 /* format_constants.h in Headers */, 43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 323F8B701F38EF770092B609 /* delta_palettization_enc.h in Headers */, - 321E60B21F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 3290FA061FA478AF0047D20C /* SDWebImageFrame.h in Headers */, 324DF4B6200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 807A122A1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, @@ -2799,6 +2819,7 @@ 80377D6B1F2F66A700F89830 /* common_sse2.h in Headers */, 320CAE172086F50500CFFC80 /* SDWebImageError.h in Headers */, 4A2CAE181AB4BB6400B6BC39 /* SDWebImageCompat.h in Headers */, + 32FDE8812088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, 80377D961F2F66A700F89830 /* msa_macro.h in Headers */, 43CE75D11CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */, 80377C391F2F666300F89830 /* huffman_utils.h in Headers */, @@ -2807,6 +2828,7 @@ 323F8B641F38EF770092B609 /* cost_enc.h in Headers */, 328BB6C32082581100760D6C /* SDDiskCache.h in Headers */, 4A2CAE1D1AB4BB6800B6BC39 /* SDWebImageDownloaderOperation.h in Headers */, + 32FDE89120888726008D7530 /* SDWebImageWebPCoder.h in Headers */, 323F8BDA1F38EF770092B609 /* vp8i_enc.h in Headers */, 4317394E1CDFC8B70008FEB9 /* decode.h in Headers */, 80377C2C1F2F666300F89830 /* bit_reader_inl_utils.h in Headers */, @@ -2831,15 +2853,14 @@ 321E60A41F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, 32CF1C091FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, 4A2CAE1B1AB4BB6800B6BC39 /* SDWebImageDownloader.h in Headers */, - 4A2CAE271AB4BB7500B6BC39 /* MKAnnotationView+WebCache.h in Headers */, 431739501CDFC8B70008FEB9 /* encode.h in Headers */, 323F8B881F38EF770092B609 /* histogram_enc.h in Headers */, 80377EB21F2F66D400F89830 /* vp8i_dec.h in Headers */, 80377EAA1F2F66D400F89830 /* common_dec.h in Headers */, 80377C451F2F666300F89830 /* utils.h in Headers */, 80377C411F2F666300F89830 /* rescaler_utils.h in Headers */, + 32FDE89720888726008D7530 /* UIImage+WebP.h in Headers */, 3248476B201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, - 4A2CAE311AB4BB7500B6BC39 /* UIImage+WebP.h in Headers */, 323F8BF81F38EF770092B609 /* animi.h in Headers */, 32D122322080B2EB003685A3 /* SDImageCachesManager.h in Headers */, 80377C351F2F666300F89830 /* filters_utils.h in Headers */, @@ -2904,13 +2925,14 @@ 32F21B5120788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 80377C011F2F665300F89830 /* filters_utils.h in Headers */, 5376131C155AD0D5005750A4 /* SDWebImageManager.h in Headers */, - 438096741CDFC09C00DC626B /* UIImage+WebP.h in Headers */, 80377BFF1F2F665300F89830 /* endian_inl_utils.h in Headers */, 80377C0F1F2F665300F89830 /* thread_utils.h in Headers */, + 32FDE8802088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, 321E60BE1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 5376131E155AD0D5005750A4 /* SDWebImagePrefetcher.h in Headers */, 32F7C06F2030114C00873181 /* SDWebImageTransformer.h in Headers */, 321B378D2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, + 32FDE8A220888789008D7530 /* SDWebImage.h in Headers */, 324DF4B4200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 80377CE11F2F66A100F89830 /* common_sse2.h in Headers */, 80377C0B1F2F665300F89830 /* random_utils.h in Headers */, @@ -2933,21 +2955,21 @@ 323F8B621F38EF770092B609 /* cost_enc.h in Headers */, 43CE75761CFE9427006C64D0 /* FLAnimatedImage.h in Headers */, 323F8BE41F38EF770092B609 /* vp8li_enc.h in Headers */, + 32FDE88F20888726008D7530 /* SDWebImageWebPCoder.h in Headers */, 320CAE152086F50500CFFC80 /* SDWebImageError.h in Headers */, 323F8B861F38EF770092B609 /* histogram_enc.h in Headers */, 321B37812083290E00C0EA77 /* SDWebImageLoader.h in Headers */, 323F8BF61F38EF770092B609 /* animi.h in Headers */, 321E60861F38E8C800405457 /* SDWebImageCoder.h in Headers */, - 321E60B01F38E90100405457 /* SDWebImageWebPCoder.h in Headers */, 80377C0D1F2F665300F89830 /* rescaler_utils.h in Headers */, 32484763201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80377E911F2F66D000F89830 /* vp8_dec.h in Headers */, 323F8B6E1F38EF770092B609 /* delta_palettization_enc.h in Headers */, - 438096721CDFC08200DC626B /* MKAnnotationView+WebCache.h in Headers */, 43CE757C1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, 32D1221E2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, 80377E8A1F2F66D000F89830 /* common_dec.h in Headers */, AB615303192DA24600A2D8E9 /* UIView+WebCacheOperation.h in Headers */, + 32FDE89520888726008D7530 /* UIImage+WebP.h in Headers */, 323F8B501F38EF770092B609 /* backward_references_enc.h in Headers */, 80377C111F2F665300F89830 /* utils.h in Headers */, 80377BFA1F2F665300F89830 /* bit_reader_utils.h in Headers */, @@ -3177,6 +3199,7 @@ buildActionMask = 2147483647; files = ( 80377DD31F2F66A700F89830 /* lossless_enc.c in Sources */, + 32FDE88C20888726008D7530 /* UIImage+WebP.m in Sources */, 323F8BBD1F38EF770092B609 /* predictor_enc.c in Sources */, 3290FA0D1FA478AF0047D20C /* SDWebImageFrame.m in Sources */, 80377DBD1F2F66A700F89830 /* dec.c in Sources */, @@ -3220,7 +3243,6 @@ 80377DCF1F2F66A700F89830 /* lossless_enc_msa.c in Sources */, 80377DD51F2F66A700F89830 /* lossless_msa.c in Sources */, 80377C4E1F2F666300F89830 /* filters_utils.c in Sources */, - 321E60B91F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 80377DEB1F2F66A700F89830 /* yuv.c in Sources */, 3237F9E920161AE000A88143 /* NSImage+Compatibility.m in Sources */, 32C0FDEA2013426C001B8F2D /* SDWebImageIndicator.m in Sources */, @@ -3283,10 +3305,10 @@ 321E608F1F38E8C800405457 /* SDWebImageCoder.m in Sources */, 00733A581BC4880000A5A117 /* SDWebImageManager.m in Sources */, 323F8B411F38EF770092B609 /* alpha_enc.c in Sources */, - 4397D2F91D0DF44A00BB2784 /* MKAnnotationView+WebCache.m in Sources */, 323F8BC31F38EF770092B609 /* quant_enc.c in Sources */, 00733A541BC4880000A5A117 /* SDWebImageCompat.m in Sources */, 80377DDF1F2F66A700F89830 /* rescaler_msa.c in Sources */, + 32FDE87E2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */, 80377DE41F2F66A700F89830 /* upsampling_msa.c in Sources */, 00733A621BC4880000A5A117 /* UIView+WebCacheOperation.m in Sources */, 80377DC21F2F66A700F89830 /* enc_msa.c in Sources */, @@ -3303,7 +3325,6 @@ 807A12311F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */, 80377C491F2F666300F89830 /* bit_writer_utils.c in Sources */, 323F8B471F38EF770092B609 /* analysis_enc.c in Sources */, - 00733A5F1BC4880000A5A117 /* UIImage+WebP.m in Sources */, 80377DB51F2F66A700F89830 /* cpu.c in Sources */, 80377EC51F2F66D500F89830 /* webp_dec.c in Sources */, 80377DD61F2F66A700F89830 /* lossless_neon.c in Sources */, @@ -3312,6 +3333,7 @@ 80377EC01F2F66D500F89830 /* vp8_dec.c in Sources */, 80377C521F2F666300F89830 /* huffman_utils.c in Sources */, 80377DD81F2F66A700F89830 /* lossless.c in Sources */, + 32FDE89E20888726008D7530 /* SDWebImageWebPCoder.m in Sources */, 80377DE11F2F66A700F89830 /* rescaler_sse2.c in Sources */, 324DF4BD200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 80377DAC1F2F66A700F89830 /* alpha_processing.c in Sources */, @@ -3385,10 +3407,10 @@ 80377D441F2F66A700F89830 /* lossless_enc_mips32.c in Sources */, 4369C27F1D9807EC007E863A /* UIView+WebCache.m in Sources */, 80377D4A1F2F66A700F89830 /* lossless_mips_dsp_r2.c in Sources */, + 32FDE88A20888726008D7530 /* UIImage+WebP.m in Sources */, 80377D4C1F2F66A700F89830 /* lossless_neon.c in Sources */, 80377D591F2F66A700F89830 /* upsampling_mips_dsp_r2.c in Sources */, 323F8BDF1F38EF770092B609 /* vp8l_enc.c in Sources */, - 4314D1341D0E0E3B004B36C9 /* UIImage+WebP.m in Sources */, 80377D3D1F2F66A700F89830 /* filters_mips_dsp_r2.c in Sources */, 323F8B751F38EF770092B609 /* filter_enc.c in Sources */, 32D122252080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, @@ -3493,10 +3515,10 @@ 4314D1521D0E0E3B004B36C9 /* NSData+ImageContentType.m in Sources */, 80377D231F2F66A700F89830 /* argb_mips_dsp_r2.c in Sources */, 4314D1531D0E0E3B004B36C9 /* UIImage+MultiFormat.m in Sources */, - 321E60B71F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 80377D5D1F2F66A700F89830 /* upsampling.c in Sources */, 80377D251F2F66A700F89830 /* argb.c in Sources */, 80377D281F2F66A700F89830 /* cost_mips32.c in Sources */, + 32FDE89C20888726008D7530 /* SDWebImageWebPCoder.m in Sources */, 323F8BF11F38EF770092B609 /* anim_encode.c in Sources */, 4314D1551D0E0E3B004B36C9 /* UIImageView+HighlightedWebCache.m in Sources */, 80377E991F2F66D400F89830 /* buffer_dec.c in Sources */, @@ -3551,6 +3573,7 @@ 323F8B841F38EF770092B609 /* histogram_enc.c in Sources */, 431BB69A1D06D2C1006A3455 /* SDWebImageDownloader.m in Sources */, 80377E131F2F66A800F89830 /* lossless_enc_mips32.c in Sources */, + 32FDE88D20888726008D7530 /* UIImage+WebP.m in Sources */, 80377E191F2F66A800F89830 /* lossless_mips_dsp_r2.c in Sources */, 80377E1B1F2F66A800F89830 /* lossless_neon.c in Sources */, 80377E281F2F66A800F89830 /* upsampling_mips_dsp_r2.c in Sources */, @@ -3620,7 +3643,6 @@ 80377DEE1F2F66A800F89830 /* alpha_processing_neon.c in Sources */, 43C892A41D9D6DDD0022038D /* demux.c in Sources */, 3237F9EA20161AE000A88143 /* NSImage+Compatibility.m in Sources */, - 431BB6B61D06D2C1006A3455 /* UIImage+WebP.m in Sources */, 80377E251F2F66A800F89830 /* rescaler_neon.c in Sources */, 32B9B541206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, 32F7C0792030114C00873181 /* SDWebImageTransformer.m in Sources */, @@ -3659,10 +3681,10 @@ 80377C651F2F666400F89830 /* color_cache_utils.c in Sources */, 431BB6C41D06D2C1006A3455 /* UIImage+MultiFormat.m in Sources */, 80377DF21F2F66A800F89830 /* argb_mips_dsp_r2.c in Sources */, - 321E60BA1F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 80377E2C1F2F66A800F89830 /* upsampling.c in Sources */, 80377DF41F2F66A800F89830 /* argb.c in Sources */, 80377DF71F2F66A800F89830 /* cost_mips32.c in Sources */, + 32FDE89F20888726008D7530 /* SDWebImageWebPCoder.m in Sources */, 323F8BF41F38EF770092B609 /* anim_encode.c in Sources */, 80377C6E1F2F666400F89830 /* quant_levels_dec_utils.c in Sources */, 80377EC91F2F66D500F89830 /* buffer_dec.c in Sources */, @@ -3686,7 +3708,6 @@ 4397D27E1D0DDD8C00BB2784 /* UIImage+GIF.m in Sources */, 321E60911F38E8C800405457 /* SDWebImageCoder.m in Sources */, 80377C8A1F2F666400F89830 /* quant_levels_utils.c in Sources */, - 4397D27F1D0DDD8C00BB2784 /* UIImage+WebP.m in Sources */, 4397D2F71D0DE2DF00BB2784 /* NSImage+Compatibility.m in Sources */, 80377E751F2F66A800F89830 /* yuv.c in Sources */, 43C892A01D9D6DDA0022038D /* anim_decode.c in Sources */, @@ -3702,6 +3723,7 @@ 80377E3E1F2F66A800F89830 /* cost.c in Sources */, 323F8BEF1F38EF770092B609 /* webp_enc.c in Sources */, 323F8BA11F38EF770092B609 /* picture_csp_enc.c in Sources */, + 32FDE87F2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */, 323F8C1F1F38EF770092B609 /* muxread.c in Sources */, 328BB6CC2082581100760D6C /* SDDiskCache.m in Sources */, 323F8C0D1F38EF770092B609 /* muxedit.c in Sources */, @@ -3721,6 +3743,7 @@ 80377E581F2F66A800F89830 /* lossless_enc_mips32.c in Sources */, 4397D28F1D0DDD8C00BB2784 /* SDWebImageDownloaderOperation.m in Sources */, 323F8BB91F38EF770092B609 /* picture_tools_enc.c in Sources */, + 32FDE8A020888726008D7530 /* SDWebImageWebPCoder.m in Sources */, 80377E451F2F66A800F89830 /* dec_sse2.c in Sources */, 80377E3F1F2F66A800F89830 /* cpu.c in Sources */, 80377E4C1F2F66A800F89830 /* enc_msa.c in Sources */, @@ -3743,9 +3766,9 @@ 80377E551F2F66A800F89830 /* filters.c in Sources */, 80377E731F2F66A800F89830 /* yuv_mips32.c in Sources */, 32D1222F2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, - 4397D2911D0DDD8C00BB2784 /* MKAnnotationView+WebCache.m in Sources */, 4397D2921D0DDD8C00BB2784 /* SDWebImagePrefetcher.m in Sources */, 323F8BBF1F38EF770092B609 /* predictor_enc.c in Sources */, + 32FDE88E20888726008D7530 /* UIImage+WebP.m in Sources */, 807A12331F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */, 323F8BD11F38EF770092B609 /* token_enc.c in Sources */, 323F8B4F1F38EF770092B609 /* backward_references_enc.c in Sources */, @@ -3827,7 +3850,6 @@ 80377E5E1F2F66A800F89830 /* lossless_mips_dsp_r2.c in Sources */, 80377E3D1F2F66A800F89830 /* cost_sse2.c in Sources */, 32F7C0832030719600873181 /* UIImage+Transform.m in Sources */, - 321E60BB1F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 80377E3C1F2F66A800F89830 /* cost_mips32.c in Sources */, 80377E421F2F66A800F89830 /* dec_mips32.c in Sources */, 32484774201775F600AF9E5A /* SDAnimatedImage.m in Sources */, @@ -3847,6 +3869,7 @@ buildActionMask = 2147483647; files = ( 80377D8E1F2F66A700F89830 /* lossless_enc.c in Sources */, + 32FDE88B20888726008D7530 /* UIImage+WebP.m in Sources */, 323F8BBC1F38EF770092B609 /* predictor_enc.c in Sources */, 3290FA0C1FA478AF0047D20C /* SDWebImageFrame.m in Sources */, 80377D781F2F66A700F89830 /* dec.c in Sources */, @@ -3872,7 +3895,6 @@ 80377D721F2F66A700F89830 /* dec_mips_dsp_r2.c in Sources */, 320CAE1D2086F50500CFFC80 /* SDWebImageError.m in Sources */, 80377D7E1F2F66A700F89830 /* enc_neon.c in Sources */, - 4A2CAE321AB4BB7500B6BC39 /* UIImage+WebP.m in Sources */, 80377DA01F2F66A700F89830 /* upsampling_neon.c in Sources */, 80377D691F2F66A700F89830 /* argb_sse2.c in Sources */, 32CF1C0F1FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */, @@ -3890,7 +3912,6 @@ 80377C341F2F666300F89830 /* filters_utils.c in Sources */, 80377D901F2F66A700F89830 /* lossless_msa.c in Sources */, 80377DA61F2F66A700F89830 /* yuv.c in Sources */, - 321E60B81F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 43CE757A1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, 3237F9E820161AE000A88143 /* NSImage+Compatibility.m in Sources */, 32C0FDE92013426C001B8F2D /* SDWebImageIndicator.m in Sources */, @@ -3926,7 +3947,6 @@ 80377D9E1F2F66A700F89830 /* upsampling_mips_dsp_r2.c in Sources */, 80377DA31F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */, 80377EAF1F2F66D400F89830 /* tree_dec.c in Sources */, - 4A2CAE281AB4BB7500B6BC39 /* MKAnnotationView+WebCache.m in Sources */, 4A2CAE261AB4BB7000B6BC39 /* SDWebImagePrefetcher.m in Sources */, 328BB6C92082581100760D6C /* SDDiskCache.m in Sources */, 3248475F201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, @@ -3958,6 +3978,7 @@ 80377D761F2F66A700F89830 /* dec_sse2.c in Sources */, 4A2CAE1C1AB4BB6800B6BC39 /* SDWebImageDownloader.m in Sources */, 4A2CAE2A1AB4BB7500B6BC39 /* NSData+ImageContentType.m in Sources */, + 32FDE87D2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */, 80377D9A1F2F66A700F89830 /* rescaler_msa.c in Sources */, 80377D9F1F2F66A700F89830 /* upsampling_msa.c in Sources */, 80377D7D1F2F66A700F89830 /* enc_msa.c in Sources */, @@ -3982,6 +4003,7 @@ 80377D911F2F66A700F89830 /* lossless_neon.c in Sources */, 80377EB01F2F66D400F89830 /* vp8_dec.c in Sources */, 80377C381F2F666300F89830 /* huffman_utils.c in Sources */, + 32FDE89D20888726008D7530 /* SDWebImageWebPCoder.m in Sources */, 80377C3A1F2F666300F89830 /* quant_levels_dec_utils.c in Sources */, 324DF4BC200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 80377D931F2F66A700F89830 /* lossless.c in Sources */, @@ -4017,6 +4039,7 @@ buildActionMask = 2147483647; files = ( 80377D041F2F66A100F89830 /* lossless_enc.c in Sources */, + 32FDE88920888726008D7530 /* UIImage+WebP.m in Sources */, 323F8BBA1F38EF770092B609 /* predictor_enc.c in Sources */, 3290FA0A1FA478AF0047D20C /* SDWebImageFrame.m in Sources */, 80377CEE1F2F66A100F89830 /* dec.c in Sources */, @@ -4059,7 +4082,6 @@ 80377C001F2F665300F89830 /* filters_utils.c in Sources */, 80377D061F2F66A100F89830 /* lossless_msa.c in Sources */, 80377D1C1F2F66A100F89830 /* yuv.c in Sources */, - 321E60B61F38E90100405457 /* SDWebImageWebPCoder.m in Sources */, 43CE75791CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, 80377CF71F2F66A100F89830 /* enc.c in Sources */, 3237F9EB20161AE000A88143 /* NSImage+Compatibility.m in Sources */, @@ -4081,7 +4103,6 @@ 323F8B561F38EF770092B609 /* config_enc.c in Sources */, 43C8929B1D9D6DD70022038D /* demux.c in Sources */, 80377D1A1F2F66A100F89830 /* yuv_mips32.c in Sources */, - 438096751CDFC0A100DC626B /* UIImage+WebP.m in Sources */, 80377E8D1F2F66D000F89830 /* io_dec.c in Sources */, 80377E8C1F2F66D000F89830 /* idec_dec.c in Sources */, 323F8B961F38EF770092B609 /* near_lossless_enc.c in Sources */, @@ -4127,12 +4148,12 @@ 80377CEC1F2F66A100F89830 /* dec_sse2.c in Sources */, 5376130F155AD0D5005750A4 /* UIImageView+WebCache.m in Sources */, 530E49EC16464C84002868E7 /* SDWebImageDownloaderOperation.m in Sources */, + 32FDE87C2088871B008D7530 /* MKAnnotationView+WebCache.m in Sources */, 80377D101F2F66A100F89830 /* rescaler_msa.c in Sources */, 80377D151F2F66A100F89830 /* upsampling_msa.c in Sources */, 80377CF31F2F66A100F89830 /* enc_msa.c in Sources */, 80377CFA1F2F66A100F89830 /* filters_neon.c in Sources */, 80377CF61F2F66A100F89830 /* enc_sse41.c in Sources */, - 438096731CDFC08F00DC626B /* MKAnnotationView+WebCache.m in Sources */, 53406750167780C40042B59E /* SDWebImageCompat.m in Sources */, 80377D171F2F66A100F89830 /* upsampling_sse2.c in Sources */, 323F8BCC1F38EF770092B609 /* token_enc.c in Sources */, @@ -4152,6 +4173,7 @@ 80377E901F2F66D000F89830 /* vp8_dec.c in Sources */, 80377C041F2F665300F89830 /* huffman_utils.c in Sources */, 80377C061F2F665300F89830 /* quant_levels_dec_utils.c in Sources */, + 32FDE89B20888726008D7530 /* SDWebImageWebPCoder.m in Sources */, 80377D091F2F66A100F89830 /* lossless.c in Sources */, 324DF4BA200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 80377D121F2F66A100F89830 /* rescaler_sse2.c in Sources */, diff --git a/SDWebImage/MKAnnotationView+WebCache.h b/SDWebImage/MapKit/MKAnnotationView+WebCache.h similarity index 100% rename from SDWebImage/MKAnnotationView+WebCache.h rename to SDWebImage/MapKit/MKAnnotationView+WebCache.h diff --git a/SDWebImage/MKAnnotationView+WebCache.m b/SDWebImage/MapKit/MKAnnotationView+WebCache.m similarity index 100% rename from SDWebImage/MKAnnotationView+WebCache.m rename to SDWebImage/MapKit/MKAnnotationView+WebCache.m diff --git a/SDWebImage/SDWebImageWebPCoder.h b/SDWebImage/WebP/SDWebImageWebPCoder.h similarity index 100% rename from SDWebImage/SDWebImageWebPCoder.h rename to SDWebImage/WebP/SDWebImageWebPCoder.h diff --git a/SDWebImage/SDWebImageWebPCoder.m b/SDWebImage/WebP/SDWebImageWebPCoder.m similarity index 100% rename from SDWebImage/SDWebImageWebPCoder.m rename to SDWebImage/WebP/SDWebImageWebPCoder.m diff --git a/SDWebImage/UIImage+WebP.h b/SDWebImage/WebP/UIImage+WebP.h similarity index 100% rename from SDWebImage/UIImage+WebP.h rename to SDWebImage/WebP/UIImage+WebP.h diff --git a/SDWebImage/UIImage+WebP.m b/SDWebImage/WebP/UIImage+WebP.m similarity index 100% rename from SDWebImage/UIImage+WebP.m rename to SDWebImage/WebP/UIImage+WebP.m diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index 82406905..ed37b422 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -49,44 +49,46 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import - -#if SD_MAC || SD_UIKIT - #import -#endif - #import #import #import #import #import #import -#import #import #import #import #import -#import #import #import #import #import #import -#if SD_MAC - #import - #import - #import +// Mac +#if __has_include() +#import +#endif +#if __has_include() +#import +#endif +#if __has_include() +#import #endif -#if SD_UIKIT - #import - - #if __has_include() - #import - #endif - - #if __has_include() - #import - #endif - +// MapKit +#if __has_include() +#import +#endif + + +// GIF +#if __has_include() +#import +#endif + +// WebP +#if __has_include() +#import +#import #endif diff --git a/WebImage/SDWebImage.modulemap b/WebImage/SDWebImage.modulemap new file mode 100644 index 00000000..871087ca --- /dev/null +++ b/WebImage/SDWebImage.modulemap @@ -0,0 +1,6 @@ +framework module SDWebImage { + umbrella header "SDWebImage.h" + + export * + module * { export * } +} From 55e4ce35bdcb9dc6142863fa48e886ab555cf36a Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 19 Apr 2018 16:23:17 +0800 Subject: [PATCH 153/361] Replace all the demo project to use `#import ` module headers instead of massive headers --- Examples/SDWebImage Demo/AppDelegate.m | 3 +-- Examples/SDWebImage Demo/DetailViewController.m | 3 +-- Examples/SDWebImage Demo/MasterViewController.m | 3 +-- Examples/SDWebImage OSX Demo/ViewController.m | 5 +---- Examples/SDWebImage TV Demo/ViewController.m | 3 +-- .../SDWebImage Watch Demo Extension/InterfaceController.m | 2 +- 6 files changed, 6 insertions(+), 13 deletions(-) diff --git a/Examples/SDWebImage Demo/AppDelegate.m b/Examples/SDWebImage Demo/AppDelegate.m index 8eb070d6..c6a005b4 100644 --- a/Examples/SDWebImage Demo/AppDelegate.m +++ b/Examples/SDWebImage Demo/AppDelegate.m @@ -7,10 +7,9 @@ */ #import "AppDelegate.h" - #import "MasterViewController.h" -#import +#import @implementation AppDelegate diff --git a/Examples/SDWebImage Demo/DetailViewController.m b/Examples/SDWebImage Demo/DetailViewController.m index c2fc9ade..a0c5ac22 100644 --- a/Examples/SDWebImage Demo/DetailViewController.m +++ b/Examples/SDWebImage Demo/DetailViewController.m @@ -7,8 +7,7 @@ */ #import "DetailViewController.h" -#import -#import +#import @interface DetailViewController () diff --git a/Examples/SDWebImage Demo/MasterViewController.m b/Examples/SDWebImage Demo/MasterViewController.m index 45e60953..504a3f49 100644 --- a/Examples/SDWebImage Demo/MasterViewController.m +++ b/Examples/SDWebImage Demo/MasterViewController.m @@ -8,8 +8,7 @@ #import "MasterViewController.h" #import "DetailViewController.h" -#import -#import +#import @interface MyCustomTableViewCell : UITableViewCell diff --git a/Examples/SDWebImage OSX Demo/ViewController.m b/Examples/SDWebImage OSX Demo/ViewController.m index a01af45c..d709b46f 100644 --- a/Examples/SDWebImage OSX Demo/ViewController.m +++ b/Examples/SDWebImage OSX Demo/ViewController.m @@ -7,10 +7,7 @@ */ #import "ViewController.h" -#import -#import - -@import SDWebImage; +#import @interface ViewController () diff --git a/Examples/SDWebImage TV Demo/ViewController.m b/Examples/SDWebImage TV Demo/ViewController.m index 16f34316..a2ad4904 100644 --- a/Examples/SDWebImage TV Demo/ViewController.m +++ b/Examples/SDWebImage TV Demo/ViewController.m @@ -7,8 +7,7 @@ */ #import "ViewController.h" -#import -#import +#import @interface ViewController () diff --git a/Examples/SDWebImage Watch Demo Extension/InterfaceController.m b/Examples/SDWebImage Watch Demo Extension/InterfaceController.m index d36cec8d..31aeb716 100644 --- a/Examples/SDWebImage Watch Demo Extension/InterfaceController.m +++ b/Examples/SDWebImage Watch Demo Extension/InterfaceController.m @@ -7,7 +7,7 @@ */ #import "InterfaceController.h" -#import +#import @interface InterfaceController() From 9c11886dc0c89852d37fd31c68e3e13a7cec585c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 19 Apr 2018 16:43:29 +0800 Subject: [PATCH 154/361] Update the test project to use modular headers instead of massive headers... --- Tests/SDWebImage Tests.xcodeproj/project.pbxproj | 2 ++ Tests/Tests/SDAnimatedImageTest.m | 6 ------ Tests/Tests/SDCategoriesTests.m | 4 ---- Tests/Tests/SDImageCacheTests.m | 3 --- Tests/Tests/SDTestCase.h | 1 + Tests/Tests/SDWebCacheCategoriesTests.m | 8 -------- Tests/Tests/SDWebImageDecoderTests.m | 10 ---------- Tests/Tests/SDWebImageDownloaderTests.m | 4 ---- Tests/Tests/SDWebImageManagerTests.m | 2 -- Tests/Tests/SDWebImagePrefetcherTests.m | 2 -- Tests/Tests/SDWebImageTransformerTests.m | 2 -- 11 files changed, 3 insertions(+), 41 deletions(-) diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 5fafa45f..63e363f3 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -612,6 +612,7 @@ DA248D4A1954721A00390AB0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -645,6 +646,7 @@ DA248D4B1954721A00390AB0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index 88da836c..7c6907a0 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -8,12 +8,6 @@ */ #import "SDTestCase.h" -#import -#import -#import -#import -#import -#import #import #if SD_MAC diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m index b49378ed..c8429284 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDCategoriesTests.m @@ -8,13 +8,9 @@ */ #import "SDTestCase.h" -#import #if SD_UIKIT #import #endif -#import -#import -#import @interface SDCategoriesTests : SDTestCase diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index bc9f3623..f884cfeb 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -7,9 +7,6 @@ */ #import "SDTestCase.h" -#import -#import -#import #import "SDWebImageTestDecoder.h" #import "SDMockFileManager.h" #import "SDWebImageTestCache.h" diff --git a/Tests/Tests/SDTestCase.h b/Tests/Tests/SDTestCase.h index dbb7c36b..566381c1 100644 --- a/Tests/Tests/SDTestCase.h +++ b/Tests/Tests/SDTestCase.h @@ -12,6 +12,7 @@ #import #import +#import FOUNDATION_EXPORT const int64_t kAsyncTestTimeout; FOUNDATION_EXPORT const int64_t kMinDelayNanosecond; diff --git a/Tests/Tests/SDWebCacheCategoriesTests.m b/Tests/Tests/SDWebCacheCategoriesTests.m index d10c1765..6e988d0e 100644 --- a/Tests/Tests/SDWebCacheCategoriesTests.m +++ b/Tests/Tests/SDWebCacheCategoriesTests.m @@ -8,14 +8,6 @@ */ #import "SDTestCase.h" -#import -#import -#import -#import -#if SD_UIKIT -#import -#endif -#import #import @interface SDWebCacheCategoriesTests : SDTestCase diff --git a/Tests/Tests/SDWebImageDecoderTests.m b/Tests/Tests/SDWebImageDecoderTests.m index 71966dae..077e2b30 100644 --- a/Tests/Tests/SDWebImageDecoderTests.m +++ b/Tests/Tests/SDWebImageDecoderTests.m @@ -8,16 +8,6 @@ */ #import "SDTestCase.h" -#import -#import -#import -#import -#import -#import -#if SD_MAC -#import -#endif -#import @interface SDWebImageDecoderTests : SDTestCase diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index 2a2d568e..fc7a70d9 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -8,10 +8,6 @@ */ #import "SDTestCase.h" -#import -#import -#import -#import #import "SDWebImageTestDownloadOperation.h" #import "SDWebImageTestDecoder.h" #import "SDWebImageTestLoader.h" diff --git a/Tests/Tests/SDWebImageManagerTests.m b/Tests/Tests/SDWebImageManagerTests.m index 3f2e397b..ef4be045 100644 --- a/Tests/Tests/SDWebImageManagerTests.m +++ b/Tests/Tests/SDWebImageManagerTests.m @@ -7,8 +7,6 @@ */ #import "SDTestCase.h" -#import -#import #import "SDWebImageTestTransformer.h" @interface SDWebImageManagerTests : SDTestCase diff --git a/Tests/Tests/SDWebImagePrefetcherTests.m b/Tests/Tests/SDWebImagePrefetcherTests.m index c6cbb3c3..98695756 100644 --- a/Tests/Tests/SDWebImagePrefetcherTests.m +++ b/Tests/Tests/SDWebImagePrefetcherTests.m @@ -8,8 +8,6 @@ */ #import "SDTestCase.h" -#import -#import @interface SDWebImagePrefetcherTests : SDTestCase diff --git a/Tests/Tests/SDWebImageTransformerTests.m b/Tests/Tests/SDWebImageTransformerTests.m index feff0241..155a70b1 100644 --- a/Tests/Tests/SDWebImageTransformerTests.m +++ b/Tests/Tests/SDWebImageTransformerTests.m @@ -8,9 +8,7 @@ */ #import "SDTestCase.h" -#import #import -#import // Internal header @interface UIColor (HexString) From 8ed4dcb884db67ede2d3527ce5d060e4e04cf0c2 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 19 Apr 2018 17:51:55 +0800 Subject: [PATCH 155/361] Fix the warning of high version API on macOS --- SDWebImage/UIImage+Transform.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 00206685..323d4f44 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -140,7 +140,7 @@ static inline CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageS static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitmapInfo) { // Get alpha info, byteOrder info CGImageAlphaInfo alphaInfo = bitmapInfo & kCGBitmapAlphaInfoMask; - CGImageByteOrderInfo byteOrderInfo = bitmapInfo & kCGBitmapByteOrderMask; + CGBitmapInfo byteOrderInfo = bitmapInfo & kCGBitmapByteOrderMask; CGFloat r = 0, g = 0, b = 0, a = 255.0; BOOL byteOrderNormal = NO; From 70d9d31c0f699448eeb5af531a65e7fd9bd93435 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 20 Apr 2018 11:05:35 +0800 Subject: [PATCH 156/361] Fix the wrong options issue --- SDWebImage/SDWebImageDefine.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index 3380c80c..0e2da0a2 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -163,13 +163,13 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { /** * By default, we decode the animated image. This flag can force decode the first frame only and produece the static image. */ - SDWebImageDecodeFirstFrameOnly = 1 << 17, + SDWebImageDecodeFirstFrameOnly = 1 << 18, /** * By default, for `SDAnimatedImage`, we decode the animated image frame during rendering to reduce memory usage. However, you can specify to preload all frames into memory to reduce CPU usage when the animated image is shared by lots of imageViews. * This will actually trigger `preloadAllAnimatedImageFrames` in the background queue(Disk Cache & Download only). */ - SDWebImagePreloadAllFrames = 1 << 18 + SDWebImagePreloadAllFrames = 1 << 19 }; From be8fce5ddb7546af5a4924d7a8e58545ef741a65 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 20 Apr 2018 11:05:53 +0800 Subject: [PATCH 157/361] Fix the download operation to specify correct error code for bad image data --- SDWebImage/SDWebImageDownloaderOperation.m | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 0c7c1747..a33778f4 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -408,10 +408,7 @@ didReceiveResponse:(NSURLResponse *)response [self done]; } else { if ([self callbacksForKey:kCompletedCallbackKey].count > 0) { - /** - * If you specified to use `NSURLCache`, then the response you get here is what you need. - */ - __block NSData *imageData = [self.imageData copy]; + NSData *imageData = [self.imageData copy]; if (imageData) { /** if you specified to only use cached data via `SDWebImageDownloaderIgnoreCachedResponse`, * then we should check if the cached data is equal to image data @@ -426,7 +423,7 @@ didReceiveResponse:(NSURLResponse *)response UIImage *image = SDWebImageLoaderDecodeImageData(imageData, self.request.URL, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); CGSize imageSize = image.size; if (imageSize.width == 0 || imageSize.height == 0) { - [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}]]; + [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorBadImageData userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}]]; } else { [self callCompletionBlocksWithImage:image imageData:imageData error:nil finished:YES]; } @@ -434,7 +431,7 @@ didReceiveResponse:(NSURLResponse *)response }); } } else { - [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Image data is nil"}]]; + [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorBadImageData userInfo:@{NSLocalizedDescriptionKey : @"Image data is nil"}]]; [self done]; } } else { From 4b69f49c138cfea76ad910e430b3e321f46823dd Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 21 Apr 2018 10:53:23 +0800 Subject: [PATCH 158/361] Rename the progressive download helper function to using `operation` instead of pass a progressive coder to make the logic more suitable for the caller --- SDWebImage/SDWebImageDownloaderOperation.m | 17 +-------------- SDWebImage/SDWebImageLoader.h | 10 ++++----- SDWebImage/SDWebImageLoader.m | 24 ++++++++++++++++++++-- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index a33778f4..97b9364a 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -341,24 +341,9 @@ didReceiveResponse:(NSURLResponse *)response // Get the finish status BOOL finished = (totalSize >= self.expectedSize); - if (!self.progressiveCoder) { - // We need to create a new instance for progressive decoding to avoid conflicts - for (idcoder in [SDWebImageCodersManager sharedManager].coders) { - if ([coder conformsToProtocol:@protocol(SDWebImageProgressiveCoder)] && - [((id)coder) canIncrementalDecodeFromData:imageData]) { - self.progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:nil]; - break; - } - } - // If we can't find any progressive coder, disable progressive download - if (!self.progressiveCoder) { - self.options &= ~SDWebImageDownloaderProgressiveDownload; - } - } - // progressive decode the image in coder queue dispatch_async(self.coderQueue, ^{ - UIImage *image = SDWebImageLoaderDecodeProgressiveImageData(data, self.request.URL, finished, self.progressiveCoder, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); + UIImage *image = SDWebImageLoaderDecodeProgressiveImageData(data, self.request.URL, finished, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); if (image) { // We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding. diff --git a/SDWebImage/SDWebImageLoader.h b/SDWebImage/SDWebImageLoader.h index dbc9ad02..ec26c61b 100644 --- a/SDWebImage/SDWebImageLoader.h +++ b/SDWebImage/SDWebImageLoader.h @@ -14,11 +14,12 @@ typedef void(^SDWebImageLoaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL); typedef void(^SDWebImageLoaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished); -#pragma mark - Context +#pragma mark - Context Options /** A `UIImage` instance from `SDWebImageManager` when you specify `SDWebImageRefreshCached` and image cache hit. - This can be a hint for image loader to load the image from network and refresh the image from remote location if needed. If the cached image is equal to the remote location one. you should call the completion with all nil args. (UIImage) + This can be a hint for image loader to load the image from network and refresh the image from remote location if needed. If the image from remote location does not change, you should call the completion with `SDWebImageErrorCacheNotModified` error. (UIImage) + @note If you don't implement `SDWebImageRefreshCached` support, you do not need to care abot this context option. */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextLoaderCachedImage; @@ -39,16 +40,15 @@ FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _ /** This is the built-in decoding process for image progressive download from network. It's used when `SDWebImageProgressiveDownload` option is set. (It's not required when your loader does not support progressive image loading) @note If you want to implement your custom loader with `loadImageWithURL:options:context:progress:completed:` API, but also want to keep compatible with SDWebImage's behavior, you'd better use this to produce image. - @param imageData The image data from the network so far. Should not be nil @param imageURL The image URL from the input. Should not be nil @param finished Pass NO to specify the download process has not finished. Pass YES when all image data has finished. - @param progressiveCoder The image progressive coder. Should not be nil. You should bind the progressive coder for each of loading operation to avoid conflict. See `SDWebImageProgressiveCoder`. + @param operation The loader operation associated with current progressive download. Why to provide this is because progressive decoding need to store the partial decoded context for each operation to avoid conflict. You should provide the operation from `loadImageWithURL:` method return value. @param options The options arg from the input @param context The context arg from the input @return The decoded progressive image for current image data load from the network */ -FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, BOOL finished, id _Nonnull progressiveCoder, SDWebImageOptions options, SDWebImageContext * _Nullable context); +FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, BOOL finished, id _Nonnull operation, SDWebImageOptions options, SDWebImageContext * _Nullable context); #pragma mark - SDWebImageLoader diff --git a/SDWebImage/SDWebImageLoader.m b/SDWebImage/SDWebImageLoader.m index c26fda1b..c47f5c58 100644 --- a/SDWebImage/SDWebImageLoader.m +++ b/SDWebImage/SDWebImageLoader.m @@ -12,6 +12,9 @@ #import "SDWebImageCoderHelper.h" #import "SDAnimatedImage.h" #import "UIImage+WebCache.h" +#import "objc/runtime.h" + +static void * SDWebImageLoaderProgressiveCoderKey = &SDWebImageLoaderProgressiveCoderKey; UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, SDWebImageOptions options, SDWebImageContext * _Nullable context) { NSCParameterAssert(imageData); @@ -69,10 +72,27 @@ UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, return image; } -UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, BOOL finished, id _Nonnull progressiveCoder, SDWebImageOptions options, SDWebImageContext * _Nullable context) { +UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, BOOL finished, id _Nonnull operation, SDWebImageOptions options, SDWebImageContext * _Nullable context) { NSCParameterAssert(imageData); NSCParameterAssert(imageURL); - NSCParameterAssert(progressiveCoder); + NSCParameterAssert(operation); + + id progressiveCoder = objc_getAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey); + if (!progressiveCoder) { + // We need to create a new instance for progressive decoding to avoid conflicts + for (idcoder in [SDWebImageCodersManager sharedManager].coders) { + if ([coder conformsToProtocol:@protocol(SDWebImageProgressiveCoder)] && + [((id)coder) canIncrementalDecodeFromData:imageData]) { + progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:nil]; + break; + } + } + objc_setAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey, progressiveCoder, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + // If we can't find any progressive coder, disable progressive download + if (!progressiveCoder) { + return nil; + } UIImage *image; id cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter]; From 8269a0cd8e2fd08f7f439c22de61c9a25b2963e6 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 20 Apr 2018 21:39:54 +0800 Subject: [PATCH 159/361] Add the ability to custom the cache namespace prefix. Which allow user to specify the correct namespace prefix by their own --- SDWebImage/SDImageCache.m | 6 +++++- SDWebImage/SDImageCacheConfig.h | 6 ++++++ SDWebImage/SDImageCacheConfig.m | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 81ed74da..175256ff 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -59,7 +59,11 @@ diskCacheDirectory:(nonnull NSString *)directory config:(nullable SDImageCacheConfig *)config { if ((self = [super init])) { - NSString *fullNamespace = [@"com.hackemist.SDImageCache." stringByAppendingString:ns]; + NSString *namespacePrefix = config.namespacePrefix; + if (!namespacePrefix) { + namespacePrefix = @""; + } + NSString *fullNamespace = [namespacePrefix stringByAppendingString:ns]; // Create IO serial queue _ioQueue = dispatch_queue_create("com.hackemist.SDImageCache", DISPATCH_QUEUE_SERIAL); diff --git a/SDWebImage/SDImageCacheConfig.h b/SDWebImage/SDImageCacheConfig.h index 2d2e28ee..fc172a58 100644 --- a/SDWebImage/SDImageCacheConfig.h +++ b/SDWebImage/SDImageCacheConfig.h @@ -72,6 +72,12 @@ */ @property (assign, nonatomic) NSUInteger maxMemoryCount; +/** + * The namespace prefix of cache. It's used to prefix the namespace you provide to the caches's initializer. You 'd better name it with reverse domain name notation and keep the final dot. + * Defautls to `com.hackemist.SDImageCache.`, which will prefix your namespace such as `default` to final `com.hackemist.SDImageCache.default`. If you specify nil, it will be treated equals to an empty string. + */ +@property (copy, nonatomic, nullable) NSString *namespacePrefix; + /** * The custom file manager for disk cache. Pass nil to let disk cache choose the proper file manager. * Defaults to nil. diff --git a/SDWebImage/SDImageCacheConfig.m b/SDWebImage/SDImageCacheConfig.m index 71110ae6..db4b194b 100644 --- a/SDWebImage/SDImageCacheConfig.m +++ b/SDWebImage/SDImageCacheConfig.m @@ -32,6 +32,7 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week _diskCacheWritingOptions = NSDataWritingAtomic; _maxCacheAge = kDefaultCacheMaxCacheAge; _maxCacheSize = 0; + _namespacePrefix = @"com.hackemist.SDImageCache."; _memoryCacheClass = [SDMemoryCache class]; _diskCacheClass = [SDDiskCache class]; } @@ -49,6 +50,7 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week config.maxCacheSize = self.maxCacheSize; config.maxMemoryCost = self.maxMemoryCost; config.maxMemoryCount = self.maxMemoryCount; + config.namespacePrefix = [self.namespacePrefix copyWithZone:zone]; config.fileManager = self.fileManager; // NSFileManager does not conform to NSCopying, just pass the reference config.memoryCacheClass = self.memoryCacheClass; config.diskCacheClass = self.diskCacheClass; From bf85c53b77a1ddf51bc739f0ef2cd50d746a1703 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 21 Apr 2018 14:33:02 +0800 Subject: [PATCH 160/361] Remove the unused header files in download operation --- SDWebImage/SDWebImageDownloaderOperation.m | 3 --- SDWebImage/SDWebImageLoader.h | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 97b9364a..fb7ab8eb 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -7,7 +7,6 @@ */ #import "SDWebImageDownloaderOperation.h" -#import "SDWebImageCodersManager.h" #import "SDWebImageError.h" #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); @@ -59,8 +58,6 @@ typedef NSMutableDictionary SDCallbacksDictionary; @property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskId; #endif -@property (strong, nonatomic, nullable) id progressiveCoder; - @end @implementation SDWebImageDownloaderOperation diff --git a/SDWebImage/SDWebImageLoader.h b/SDWebImage/SDWebImageLoader.h index ec26c61b..7ec47ac5 100644 --- a/SDWebImage/SDWebImageLoader.h +++ b/SDWebImage/SDWebImageLoader.h @@ -40,6 +40,7 @@ FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _ /** This is the built-in decoding process for image progressive download from network. It's used when `SDWebImageProgressiveDownload` option is set. (It's not required when your loader does not support progressive image loading) @note If you want to implement your custom loader with `loadImageWithURL:options:context:progress:completed:` API, but also want to keep compatible with SDWebImage's behavior, you'd better use this to produce image. + @param imageData The image data from the network so far. Should not be nil @param imageURL The image URL from the input. Should not be nil @param finished Pass NO to specify the download process has not finished. Pass YES when all image data has finished. From cfd68422dc8134927ae3e363b5c4f1543eadc245 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 20 Apr 2018 03:26:55 +0800 Subject: [PATCH 161/361] Refactor current manager's internal implementation for that `loadImageWithURL:`. Separate to 3 parts (context preprocess, cache process, download process). Also introduce `SDWebImageFromLoaderOnly` feature to ignore cache at all This is useful for some custom image loader where user does not need memory cache at all. --- SDWebImage/SDWebImageDefine.h | 15 +- SDWebImage/SDWebImageDownloader.h | 3 +- SDWebImage/SDWebImageDownloaderOperation.m | 18 +- SDWebImage/SDWebImageError.h | 4 + SDWebImage/SDWebImageError.m | 1 + SDWebImage/SDWebImageManager.m | 351 +++++++++++---------- 6 files changed, 218 insertions(+), 174 deletions(-) diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index 0e2da0a2..c604ad80 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -145,31 +145,36 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { SDWebImageQueryDiskSync = 1 << 14, /** - * By default, when the cache missed, the image is download from the network. This flag can prevent network to load from cache only. + * By default, when the cache missed, the image is load from the loader. This flag can prevent this to load from cache only. */ SDWebImageFromCacheOnly = 1 << 15, + /** + * By default, we query the cache before the image is load from the loader. This flag can prevent this to load from loader only. + */ + SDWebImageFromLoaderOnly = 1 << 16, + /** * By default, when you use `SDWebImageTransition` to do some view transition after the image load finished, this transition is only applied for image download from the network. This mask can force to apply view transition for memory and disk cache as well. */ - SDWebImageForceTransition = 1 << 16, + SDWebImageForceTransition = 1 << 17, /** * By default, we will decode the image in the background during cache query and download from the network. This can help to improve performance because when rendering image on the screen, it need to be firstly decoded. But this happen on the main queue by Core Animation. * However, this process may increase the memory usage as well. If you are experiencing a issue due to excessive memory consumption, This flag can prevent decode the image. */ - SDWebImageAvoidDecodeImage = 1 << 17, + SDWebImageAvoidDecodeImage = 1 << 18, /** * By default, we decode the animated image. This flag can force decode the first frame only and produece the static image. */ - SDWebImageDecodeFirstFrameOnly = 1 << 18, + SDWebImageDecodeFirstFrameOnly = 1 << 19, /** * By default, for `SDAnimatedImage`, we decode the animated image frame during rendering to reduce memory usage. However, you can specify to preload all frames into memory to reduce CPU usage when the animated image is shared by lots of imageViews. * This will actually trigger `preloadAllAnimatedImageFrames` in the background queue(Disk Cache & Download only). */ - SDWebImagePreloadAllFrames = 1 << 19 + SDWebImagePreloadAllFrames = 1 << 20 }; diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 03622749..b5f428d8 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -33,7 +33,8 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { /** * Call completion block with nil image/imageData if the image was read from NSURLCache - * (to be combined with `SDWebImageDownloaderUseNSURLCache`). + * And the error code is `SDWebImageErrorCacheNotModified` + * This flag should be combined with `SDWebImageDownloaderUseNSURLCache`. */ SDWebImageDownloaderIgnoreCachedResponse = 1 << 3, diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index fb7ab8eb..f55f14c6 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -42,6 +42,7 @@ typedef NSMutableDictionary SDCallbacksDictionary; @property (copy, nonatomic, nullable) NSData *cachedData; // for `SDWebImageDownloaderIgnoreCachedResponse` @property (assign, nonatomic, readwrite) NSUInteger expectedSize; @property (strong, nonatomic, nullable, readwrite) NSURLResponse *response; +@property (strong, nonatomic, nullable) NSError *responseError; // This is weak because it is injected by whoever manages this session. If this gets nil-ed out, we won't be able to run // the task associated with this operation @@ -298,11 +299,15 @@ didReceiveResponse:(NSURLResponse *)response self.expectedSize = expected; self.response = response; NSInteger statusCode = [response respondsToSelector:@selector(statusCode)] ? ((NSHTTPURLResponse *)response).statusCode : 200; - BOOL valid = statusCode < 400; - //'304 Not Modified' is an exceptional one. It should be treated as cancelled if no cache data + BOOL valid = statusCode >= 200 && statusCode < 400; + if (!valid) { + self.responseError = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidDownloadStatusCode userInfo:@{SDWebImageErrorDownloadStatusCodeKey : @(statusCode)}]; + } + //'304 Not Modified' is an exceptional one //URLSession current behavior will return 200 status code when the server respond 304 and URLCache hit. But this is not a standard behavior and we just add a check if (statusCode == 304 && !self.cachedData) { valid = NO; + self.responseError = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorCacheNotModified userInfo:nil]; } if (valid) { @@ -386,6 +391,10 @@ didReceiveResponse:(NSURLResponse *)response // make sure to call `[self done]` to mark operation as finished if (error) { + // custom error instead of URLSession error + if (self.responseError) { + error = self.responseError; + } [self callCompletionBlocksWithError:error]; [self done]; } else { @@ -396,8 +405,9 @@ didReceiveResponse:(NSURLResponse *)response * then we should check if the cached data is equal to image data */ if (self.options & SDWebImageDownloaderIgnoreCachedResponse && [self.cachedData isEqualToData:imageData]) { - // call completion block with nil - [self callCompletionBlocksWithImage:nil imageData:nil error:nil finished:YES]; + self.responseError = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorCacheNotModified userInfo:nil]; + // call completion block with not modified error + [self callCompletionBlocksWithError:self.responseError]; [self done]; } else { // decode the image in coder queue diff --git a/SDWebImage/SDWebImageError.h b/SDWebImage/SDWebImageError.h index 50929e90..1b18d7c6 100644 --- a/SDWebImage/SDWebImageError.h +++ b/SDWebImage/SDWebImageError.h @@ -11,8 +11,12 @@ FOUNDATION_EXPORT NSErrorDomain const _Nonnull SDWebImageErrorDomain; +FOUNDATION_EXPORT NSErrorUserInfoKey const _Nonnull SDWebImageErrorDownloadStatusCodeKey; + typedef NS_ERROR_ENUM(SDWebImageErrorDomain, SDWebImageError) { SDWebImageErrorInvalidURL = 1000, // The URL is invalid, such as nil URL or corrupted URL SDWebImageErrorBadImageData = 1001, // The image data can not be decoded to image, or the image data is empty + SDWebImageErrorCacheNotModified = 1002, // The remote location specify that the cached image is not modified, such as the HTTP response 304 code. It's useful for `SDWebImageRefreshCached` SDWebImageErrorInvalidDownloadOperation = 2000, // The image download operation is invalid, such as nil operation or unexpected error occur when operation initialized + SDWebImageErrorInvalidDownloadStatusCode = 2001, // The image downloda response a invalid status code. You can check the status code in error's userInfo under `SDWebImageErrorDownloadStatusCodeKey` }; diff --git a/SDWebImage/SDWebImageError.m b/SDWebImage/SDWebImageError.m index ba154c5a..6d174769 100644 --- a/SDWebImage/SDWebImageError.m +++ b/SDWebImage/SDWebImageError.m @@ -10,3 +10,4 @@ #import "SDWebImageError.h" NSErrorDomain const _Nonnull SDWebImageErrorDomain = @"SDWebImageErrorDomain"; +NSErrorUserInfoKey const _Nonnull SDWebImageErrorDownloadStatusCodeKey = @"SDWebImageErrorDownloadStatusCodeKey"; diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index a5332f8e..92a7f470 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -151,171 +151,11 @@ static id _defaultImageLoader; [self.runningOperations addObject:operation]; } - // Image transformer - id transformer; - if ([context valueForKey:SDWebImageContextCustomTransformer]) { - transformer = [context valueForKey:SDWebImageContextCustomTransformer]; - } else if (self.transformer) { - // Transformer from manager - transformer = self.transformer; - SDWebImageMutableContext *mutableContext; - if (context) { - mutableContext = [context mutableCopy]; - } else { - mutableContext = [NSMutableDictionary dictionary]; - } - [mutableContext setValue:transformer forKey:SDWebImageContextCustomTransformer]; - context = [mutableContext copy]; - } - // Cache key filter - id cacheKeyFilter; - if ([context valueForKey:SDWebImageContextCacheKeyFilter]) { - cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter]; - } else { - cacheKeyFilter = self.cacheKeyFilter; - } - NSString *key = [self cacheKeyForURL:url cacheKeyFilter:cacheKeyFilter]; - // Cache serializer - id cacheSerializer; - if ([context valueForKey:SDWebImageContextCacheSerializer]) { - cacheSerializer = [context valueForKey:SDWebImageContextCacheSerializer]; - } else { - cacheSerializer = self.cacheSerializer; - } + // Preprocess the context arg to provide the default value from manager + context = [self processedContextWithContext:context]; - __weak SDWebImageCombinedOperation *weakOperation = operation; - operation.cacheOperation = [self.imageCache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable cachedImage, NSData * _Nullable cachedData, SDImageCacheType cacheType) { - __strong __typeof(weakOperation) strongOperation = weakOperation; - if (!strongOperation || strongOperation.isCancelled) { - [self safelyRemoveOperationFromRunning:strongOperation]; - return; - } - - // Check whether we should download image from network - BOOL shouldDownload = (!(options & SDWebImageFromCacheOnly)) - && (!cachedImage || options & SDWebImageRefreshCached) - && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]); - // Check whether image downloader support target URL - shouldDownload &= [self.imageLoader canLoadWithURL:url]; - if (shouldDownload) { - SDWebImageContext *downloadContext = context; - if (cacheKeyFilter) { - // Pass the cache key filter to the image loader. - SDWebImageMutableContext *mutableContext; - if (downloadContext) { - mutableContext = [downloadContext mutableCopy]; - } else { - mutableContext = [NSMutableDictionary dictionary]; - } - [mutableContext setValue:cacheKeyFilter forKey:SDWebImageContextCacheKeyFilter]; - downloadContext = [mutableContext copy]; - } - if (cachedImage && options & SDWebImageRefreshCached) { - // If image was found in the cache but SDWebImageRefreshCached is provided, notify about the cached image - // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server. - [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url]; - // Pass the cached image to the image loader. The image loader should check whether the remote image is equal to the cached image. - SDWebImageMutableContext *mutableContext; - if (downloadContext) { - mutableContext = [downloadContext mutableCopy]; - } else { - mutableContext = [NSMutableDictionary dictionary]; - } - [mutableContext setValue:cachedImage forKey:SDWebImageContextLoaderCachedImage]; - downloadContext = [mutableContext copy]; - } - - // `SDWebImageCombinedOperation` -> `SDWebImageDownloadToken` -> `downloadOperationCancelToken`, which is a `SDCallbacksDictionary` and retain the completed block below, so we need weak-strong again to avoid retain cycle - __weak typeof(strongOperation) weakSubOperation = strongOperation; - strongOperation.downloadOperation = [self.imageLoader loadImageWithURL:url options:options context:downloadContext progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { - __strong typeof(weakSubOperation) strongSubOperation = weakSubOperation; - if (!strongSubOperation || strongSubOperation.isCancelled) { - // Do nothing if the operation was cancelled - // See #699 for more details - // if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data - } else if (error) { - [self callCompletionBlockForOperation:strongSubOperation completion:completedBlock error:error url:url]; - BOOL shouldBlockFailedURL; - // Check whether we should block failed url - if ([self.delegate respondsToSelector:@selector(imageManager:shouldBlockFailedURL:withError:)]) { - shouldBlockFailedURL = [self.delegate imageManager:self shouldBlockFailedURL:url withError:error]; - } else { - shouldBlockFailedURL = ( error.code != NSURLErrorNotConnectedToInternet - && error.code != NSURLErrorCancelled - && error.code != NSURLErrorTimedOut - && error.code != NSURLErrorInternationalRoamingOff - && error.code != NSURLErrorDataNotAllowed - && error.code != NSURLErrorCannotFindHost - && error.code != NSURLErrorCannotConnectToHost - && error.code != NSURLErrorNetworkConnectionLost); - } - - if (shouldBlockFailedURL) { - @synchronized (self.failedURLs) { - [self.failedURLs addObject:url]; - } - } - } - else { - if ((options & SDWebImageRetryFailed)) { - @synchronized (self.failedURLs) { - [self.failedURLs removeObject:url]; - } - } - - SDImageCacheType storeCacheType = SDImageCacheTypeAll; - if (options & SDWebImageCacheMemoryOnly) { - storeCacheType = SDImageCacheTypeMemory; - } - if (options & SDWebImageRefreshCached && cachedImage && !downloadedImage) { - // Image refresh hit the NSURLCache cache, do not call the completion block - } else if (downloadedImage && (!downloadedImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage)) && transformer) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - UIImage *transformedImage = [transformer transformedImageWithImage:downloadedImage forKey:key]; - if (transformedImage && finished) { - NSString *transformerKey = [transformer transformerKey]; - NSString *cacheKey = SDTransformedKeyForKey(key, transformerKey); - BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage]; - NSData *cacheData; - // pass nil if the image was transformed, so we can recalculate the data from the image - if (cacheSerializer) { - cacheData = [cacheSerializer cacheDataWithImage:transformedImage originalData:(imageWasTransformed ? nil : downloadedData) imageURL:url]; - } else { - cacheData = (imageWasTransformed ? nil : downloadedData); - } - [self.imageCache storeImage:transformedImage imageData:cacheData forKey:cacheKey cacheType:storeCacheType completion:nil]; - } - - [self callCompletionBlockForOperation:strongSubOperation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; - }); - } else { - if (downloadedImage && finished) { - if (cacheSerializer) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - NSData *cacheData = [cacheSerializer cacheDataWithImage:downloadedImage originalData:downloadedData imageURL:url]; - [self.imageCache storeImage:downloadedImage imageData:cacheData forKey:key cacheType:storeCacheType completion:nil]; - }); - } else { - [self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key cacheType:storeCacheType completion:nil]; - } - } - [self callCompletionBlockForOperation:strongSubOperation completion:completedBlock image:downloadedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; - } - } - - if (finished) { - [self safelyRemoveOperationFromRunning:strongSubOperation]; - } - }]; - } else if (cachedImage) { - [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url]; - [self safelyRemoveOperationFromRunning:strongOperation]; - } else { - // Image not in cache and download disallowed by delegate - [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:nil data:nil error:nil cacheType:SDImageCacheTypeNone finished:YES url:url]; - [self safelyRemoveOperationFromRunning:strongOperation]; - } - }]; + // Start the entry to load image from cache + [self callCacheProcessForOperation:operation url:url options:options context:context progress:progressBlock completed:completedBlock]; return operation; } @@ -336,6 +176,162 @@ static id _defaultImageLoader; return isRunning; } +#pragma mark - Private + +- (void)callCacheProcessForOperation:(nonnull SDWebImageCombinedOperation *)operation + url:(nullable NSURL *)url + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDInternalCompletionBlock)completedBlock { + // Check whether we should query cache + BOOL shouldQueryCache = (options & SDWebImageFromLoaderOnly) == 0; + if (shouldQueryCache) { + id cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter]; + NSString *key = [self cacheKeyForURL:url cacheKeyFilter:cacheKeyFilter]; + __weak SDWebImageCombinedOperation *weakOperation = operation; + operation.cacheOperation = [self.imageCache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable cachedImage, NSData * _Nullable cachedData, SDImageCacheType cacheType) { + __strong __typeof(weakOperation) strongOperation = weakOperation; + if (!strongOperation || strongOperation.isCancelled) { + [self safelyRemoveOperationFromRunning:strongOperation]; + return; + } + // Continue download process + [self callDownloadProcessForOperation:strongOperation url:url options:options context:context cachedImage:cachedImage cachedData:cachedData cacheType:cacheType progress:progressBlock completed:completedBlock]; + }]; + } else { + // Continue download process + [self callDownloadProcessForOperation:operation url:url options:options context:context cachedImage:nil cachedData:nil cacheType:SDImageCacheTypeNone progress:progressBlock completed:completedBlock]; + } +} + +- (void)callDownloadProcessForOperation:(nonnull SDWebImageCombinedOperation *)operation + url:(nullable NSURL *)url + options:(SDWebImageOptions)options + context:(SDWebImageContext *)context + cachedImage:(nullable UIImage *)cachedImage + cachedData:(nullable NSData *)cachedData + cacheType:(SDImageCacheType)cacheType + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDInternalCompletionBlock)completedBlock { + // Check whether we should download image from network + BOOL shouldDownload = (options & SDWebImageFromCacheOnly) == 0; + shouldDownload &= (!cachedImage || options & SDWebImageRefreshCached); + shouldDownload &= (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]); + shouldDownload &= [self.imageLoader canLoadWithURL:url]; + if (shouldDownload) { + if (cachedImage && options & SDWebImageRefreshCached) { + // If image was found in the cache but SDWebImageRefreshCached is provided, notify about the cached image + // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server. + [self callCompletionBlockForOperation:operation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url]; + // Pass the cached image to the image loader. The image loader should check whether the remote image is equal to the cached image. + SDWebImageMutableContext *mutableContext; + if (context) { + mutableContext = [context mutableCopy]; + } else { + mutableContext = [NSMutableDictionary dictionary]; + } + [mutableContext setValue:cachedImage forKey:SDWebImageContextLoaderCachedImage]; + context = [mutableContext copy]; + } + + // `SDWebImageCombinedOperation` -> `SDWebImageDownloadToken` -> `downloadOperationCancelToken`, which is a `SDCallbacksDictionary` and retain the completed block below, so we need weak-strong again to avoid retain cycle + __weak typeof(operation) weakOperation = operation; + operation.downloadOperation = [self.imageLoader loadImageWithURL:url options:options context:context progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { + __strong typeof(weakOperation) strongOperation = weakOperation; + if (!strongOperation || strongOperation.isCancelled) { + // Do nothing if the operation was cancelled + // See #699 for more details + // if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data + } else if (cachedImage && options & SDWebImageRefreshCached && [error.domain isEqualToString:SDWebImageErrorDomain] && error.code == SDWebImageErrorCacheNotModified) { + // Image refresh hit the NSURLCache cache, do not call the completion block + } else if (error) { + [self callCompletionBlockForOperation:strongOperation completion:completedBlock error:error url:url]; + BOOL shouldBlockFailedURL; + // Check whether we should block failed url + if ([self.delegate respondsToSelector:@selector(imageManager:shouldBlockFailedURL:withError:)]) { + shouldBlockFailedURL = [self.delegate imageManager:self shouldBlockFailedURL:url withError:error]; + } else { + shouldBlockFailedURL = ( error.code != NSURLErrorNotConnectedToInternet + && error.code != NSURLErrorCancelled + && error.code != NSURLErrorTimedOut + && error.code != NSURLErrorInternationalRoamingOff + && error.code != NSURLErrorDataNotAllowed + && error.code != NSURLErrorCannotFindHost + && error.code != NSURLErrorCannotConnectToHost + && error.code != NSURLErrorNetworkConnectionLost); + } + + if (shouldBlockFailedURL) { + @synchronized (self.failedURLs) { + [self.failedURLs addObject:url]; + } + } + } else { + if ((options & SDWebImageRetryFailed)) { + @synchronized (self.failedURLs) { + [self.failedURLs removeObject:url]; + } + } + + SDImageCacheType storeCacheType = SDImageCacheTypeAll; + if (options & SDWebImageCacheMemoryOnly) { + storeCacheType = SDImageCacheTypeMemory; + } + id cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter]; + NSString *key = [self cacheKeyForURL:url cacheKeyFilter:cacheKeyFilter]; + id transformer = [context valueForKey:SDWebImageContextCustomTransformer]; + id cacheSerializer = [context valueForKey:SDWebImageContextCacheKeyFilter]; + if (downloadedImage && (!downloadedImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage)) && transformer) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + UIImage *transformedImage = [transformer transformedImageWithImage:downloadedImage forKey:key]; + if (transformedImage && finished) { + NSString *transformerKey = [transformer transformerKey]; + NSString *cacheKey = SDTransformedKeyForKey(key, transformerKey); + BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage]; + NSData *cacheData; + // pass nil if the image was transformed, so we can recalculate the data from the image + if (cacheSerializer) { + cacheData = [cacheSerializer cacheDataWithImage:transformedImage originalData:(imageWasTransformed ? nil : downloadedData) imageURL:url]; + } else { + cacheData = (imageWasTransformed ? nil : downloadedData); + } + [self.imageCache storeImage:transformedImage imageData:cacheData forKey:cacheKey cacheType:storeCacheType completion:nil]; + } + + [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; + }); + } else { + if (downloadedImage && finished) { + if (cacheSerializer) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + NSData *cacheData = [cacheSerializer cacheDataWithImage:downloadedImage originalData:downloadedData imageURL:url]; + [self.imageCache storeImage:downloadedImage imageData:cacheData forKey:key cacheType:storeCacheType completion:nil]; + }); + } else { + [self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key cacheType:storeCacheType completion:nil]; + } + } + [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:downloadedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; + } + } + + if (finished) { + [self safelyRemoveOperationFromRunning:strongOperation]; + } + }]; + } else if (cachedImage) { + [self callCompletionBlockForOperation:operation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url]; + [self safelyRemoveOperationFromRunning:operation]; + } else { + // Image not in cache and download disallowed by delegate + [self callCompletionBlockForOperation:operation completion:completedBlock image:nil data:nil error:nil cacheType:SDImageCacheTypeNone finished:YES url:url]; + [self safelyRemoveOperationFromRunning:operation]; + } +} + +#pragma mark - Helper + - (void)safelyRemoveOperationFromRunning:(nullable SDWebImageCombinedOperation*)operation { @synchronized (self.runningOperations) { if (operation) { @@ -366,6 +362,33 @@ static id _defaultImageLoader; }); } +- (SDWebImageContext *)processedContextWithContext:(SDWebImageContext *)context { + SDWebImageMutableContext *mutableContext = [SDWebImageMutableContext dictionary]; + + // Image Transformer from manager + if (![context valueForKey:SDWebImageContextCustomTransformer]) { + id transformer = self.transformer; + [mutableContext setValue:transformer forKey:SDWebImageContextCustomTransformer]; + } + // Cache key filter from manager + if (![context valueForKey:SDWebImageContextCacheKeyFilter]) { + id cacheKeyFilter = self.cacheKeyFilter; + [mutableContext setValue:cacheKeyFilter forKey:SDWebImageContextCacheKeyFilter]; + } + // Cache serializer from manager + if (![context valueForKey:SDWebImageContextCacheSerializer]) { + id cacheSerializer = self.cacheSerializer; + [mutableContext setValue:cacheSerializer forKey:SDWebImageContextCacheSerializer]; + } + + if (mutableContext.count == 0) { + return context; + } else { + [mutableContext addEntriesFromDictionary:context]; + return [mutableContext copy]; + } +} + @end From 072b832375de01cd1ad7b8e7575035a5604a2c36 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 25 Apr 2018 12:59:44 +0800 Subject: [PATCH 162/361] Fix the issue for progressive decoding that do not parse the correct animated image scale. Update all coders --- SDWebImage/SDWebImageAPNGCoder.m | 16 +++++-- SDWebImage/SDWebImageCoder.h | 4 +- SDWebImage/SDWebImageDownloaderOperation.m | 4 +- SDWebImage/SDWebImageGIFCoder.m | 13 ++++- SDWebImage/SDWebImageImageIOCoder.m | 55 +++++++++++----------- SDWebImage/SDWebImageLoader.m | 33 +++++++------ SDWebImage/WebP/SDWebImageWebPCoder.m | 15 ++++-- 7 files changed, 79 insertions(+), 61 deletions(-) diff --git a/SDWebImage/SDWebImageAPNGCoder.m b/SDWebImage/SDWebImageAPNGCoder.m index 6d5c03c9..61da3715 100644 --- a/SDWebImage/SDWebImageAPNGCoder.m +++ b/SDWebImage/SDWebImageAPNGCoder.m @@ -33,9 +33,6 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef @implementation SDWebImageAPNGCoder { size_t _width, _height; -#if SD_UIKIT || SD_WATCH - UIImageOrientation _orientation; -#endif CGImageSourceRef _imageSource; NSData *_imageData; CGFloat _scale; @@ -246,7 +243,16 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef - (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options { self = [super init]; if (self) { - _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)}); + CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatPNG]; + _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceTypeIdentifierHint : (__bridge_transfer NSString *)imageUTType}); + CGFloat scale = 1; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if (scale < 1) { + scale = 1; + } + } + _scale = scale; #if SD_UIKIT [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; #endif @@ -290,7 +296,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL); if (partialImageRef) { - CGFloat scale = 1; + CGFloat scale = _scale; if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { diff --git a/SDWebImage/SDWebImageCoder.h b/SDWebImage/SDWebImageCoder.h index a0297477..6de19eca 100644 --- a/SDWebImage/SDWebImageCoder.h +++ b/SDWebImage/SDWebImageCoder.h @@ -114,7 +114,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp Because incremental decoding need to keep the decoded context, we will alloc a new instance with the same class for each download operation to avoid conflicts This init method should not return nil - @param options A dictionary containing any progressive decoding options (instance-level). Currentlly there is no options for this and always pass nil. Kept for extensibility. + @param options A dictionary containing any progressive decoding options (instance-level). Pass @{SDWebImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for progressive animated image (each frames should use the same scale). @return A new instance to do incremental decoding for the specify image format */ - (nonnull instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options; @@ -129,7 +129,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp /** Incremental decode the current image data to image. - @note Due to the performance issue for progressive decoding and the integration for image view. This method may only return the first frame image even if the image data is animated image. If you want progressive animated image decoding, also conform to `SDWebImageAnimatedCoder` and use `animatedImageFrameAtIndex` instead. + @note Due to the performance issue for progressive decoding and the integration for image view. This method may only return the first frame image even if the image data is animated image. If you want progressive animated image decoding, conform to `SDWebImageAnimatedCoder` protocol as well and use `animatedImageFrameAtIndex:` instead. @param options A dictionary containing any progressive decoding options. Pass @{SDWebImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for progressive image @return The decoded image from current data diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index f55f14c6..5a3dd465 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -337,7 +337,7 @@ didReceiveResponse:(NSURLResponse *)response if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0) { // Get the image data - __block NSData *imageData = [self.imageData copy]; + NSData *imageData = [self.imageData copy]; // Get the total bytes downloaded const NSUInteger totalSize = imageData.length; // Get the finish status @@ -345,7 +345,7 @@ didReceiveResponse:(NSURLResponse *)response // progressive decode the image in coder queue dispatch_async(self.coderQueue, ^{ - UIImage *image = SDWebImageLoaderDecodeProgressiveImageData(data, self.request.URL, finished, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); + UIImage *image = SDWebImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, finished, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); if (image) { // We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding. diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index fb7523e9..25d76028 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -183,7 +183,16 @@ - (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options { self = [super init]; if (self) { - _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)}); + CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatGIF]; + _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceTypeIdentifierHint : (__bridge_transfer NSString *)imageUTType}); + CGFloat scale = 1; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if (scale < 1) { + scale = 1; + } + } + _scale = scale; #if SD_UIKIT [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; #endif @@ -227,7 +236,7 @@ CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL); if (partialImageRef) { - CGFloat scale = 1; + CGFloat scale = _scale; if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index 422aec00..e35d2f7f 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -14,13 +14,9 @@ @implementation SDWebImageImageIOCoder { size_t _width, _height; -#if SD_UIKIT || SD_WATCH - UIImageOrientation _orientation; -#else CGImagePropertyOrientation _orientation; -#endif CGImageSourceRef _imageSource; - NSUInteger _frameCount; + CGFloat _scale; BOOL _finished; } @@ -37,9 +33,7 @@ - (void)didReceiveMemoryWarning:(NSNotification *)notification { if (_imageSource) { - for (size_t i = 0; i < _frameCount; i++) { - CGImageSourceRemoveCacheAtIndex(_imageSource, i); - } + CGImageSourceRemoveCacheAtIndex(_imageSource, 0); } } @@ -66,19 +60,6 @@ } } -- (BOOL)canIncrementalDecodeFromData:(NSData *)data { - switch ([NSData sd_imageFormatForImageData:data]) { - case SDImageFormatWebP: - // Do not support WebP progressive decoding - return NO; - case SDImageFormatHEIC: - // Check HEIC decoding compatibility - return [[self class] canDecodeFromHEICFormat]; - default: - return YES; - } -} - - (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { if (!data) { return nil; @@ -96,10 +77,32 @@ } #pragma mark - Progressive Decode + +- (BOOL)canIncrementalDecodeFromData:(NSData *)data { + switch ([NSData sd_imageFormatForImageData:data]) { + case SDImageFormatWebP: + // Do not support WebP progressive decoding + return NO; + case SDImageFormatHEIC: + // Check HEIC decoding compatibility + return [[self class] canDecodeFromHEICFormat]; + default: + return YES; + } +} + - (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options { self = [super init]; if (self) { _imageSource = CGImageSourceCreateIncremental(NULL); + CGFloat scale = 1; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if (scale < 1) { + scale = 1; + } + } + _scale = scale; #if SD_UIKIT [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; #endif @@ -118,7 +121,6 @@ // Update the data source, we must pass ALL the data, not just the new bytes CGImageSourceUpdateData(_imageSource, (__bridge CFDataRef)data, finished); - _frameCount = CGImageSourceGetCount(_imageSource); if (_width + _height == 0) { CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(_imageSource, 0, NULL); @@ -136,11 +138,7 @@ // which means the image below born of initWithCGIImage will be // oriented incorrectly sometimes. (Unlike the image born of initWithData // in didCompleteWithError.) So save it here and pass it on later. -#if SD_UIKIT || SD_WATCH - _orientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:(CGImagePropertyOrientation)orientationValue]; -#else _orientation = (CGImagePropertyOrientation)orientationValue; -#endif } } } @@ -172,7 +170,7 @@ #endif if (partialImageRef) { - CGFloat scale = 1; + CGFloat scale = _scale; if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { @@ -180,7 +178,8 @@ } } #if SD_UIKIT || SD_WATCH - image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:_orientation]; + UIImageOrientation imageOrientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:_orientation]; + image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:imageOrientation]; #else image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:_orientation]; #endif diff --git a/SDWebImage/SDWebImageLoader.m b/SDWebImage/SDWebImageLoader.m index c47f5c58..f9741b36 100644 --- a/SDWebImage/SDWebImageLoader.m +++ b/SDWebImage/SDWebImageLoader.m @@ -77,23 +77,6 @@ UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull NSCParameterAssert(imageURL); NSCParameterAssert(operation); - id progressiveCoder = objc_getAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey); - if (!progressiveCoder) { - // We need to create a new instance for progressive decoding to avoid conflicts - for (idcoder in [SDWebImageCodersManager sharedManager].coders) { - if ([coder conformsToProtocol:@protocol(SDWebImageProgressiveCoder)] && - [((id)coder) canIncrementalDecodeFromData:imageData]) { - progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:nil]; - break; - } - } - objc_setAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey, progressiveCoder, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - } - // If we can't find any progressive coder, disable progressive download - if (!progressiveCoder) { - return nil; - } - UIImage *image; id cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter]; NSString *cacheKey; @@ -108,6 +91,22 @@ UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull if (scale < 1) { scale = 1; } + id progressiveCoder = objc_getAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey); + if (!progressiveCoder) { + // We need to create a new instance for progressive decoding to avoid conflicts + for (idcoder in [SDWebImageCodersManager sharedManager].coders.reverseObjectEnumerator) { + if ([coder conformsToProtocol:@protocol(SDWebImageProgressiveCoder)] && + [((id)coder) canIncrementalDecodeFromData:imageData]) { + progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:@{SDWebImageCoderDecodeScaleFactor : @(scale)}]; + break; + } + } + objc_setAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey, progressiveCoder, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + // If we can't find any progressive coder, disable progressive download + if (!progressiveCoder) { + return nil; + } [progressiveCoder updateIncrementalData:imageData finished:finished]; if (!decodeFirstFrame) { diff --git a/SDWebImage/WebP/SDWebImageWebPCoder.m b/SDWebImage/WebP/SDWebImageWebPCoder.m index a0ec4792..4ed071e0 100644 --- a/SDWebImage/WebP/SDWebImageWebPCoder.m +++ b/SDWebImage/WebP/SDWebImageWebPCoder.m @@ -211,6 +211,14 @@ dispatch_semaphore_signal(self->_lock); if (self) { // Progressive images need transparent, so always use premultiplied RGBA _idec = WebPINewRGB(MODE_bgrA, NULL, 0, 0); + CGFloat scale = 1; + if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if (scale < 1) { + scale = 1; + } + } + _scale = scale; } return self; } @@ -225,10 +233,7 @@ dispatch_semaphore_signal(self->_lock); if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) { return; } -} - -- (BOOL)incrementalFinished { - return _finished; + // libwebp current does not support progressive decoding for animated image, so no need to scan and update the frame information } - (UIImage *)incrementalDecodedImageWithOptions:(SDWebImageCoderOptions *)options { @@ -278,7 +283,7 @@ dispatch_semaphore_signal(self->_lock); CGContextRelease(canvas); return nil; } - CGFloat scale = 1; + CGFloat scale = _scale; if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { From 0832da8d7c08537ac70841fcfeaac630842f51c3 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 25 Apr 2018 13:14:44 +0800 Subject: [PATCH 163/361] Avoid duplicated force decode for progressive WebP images --- SDWebImage/WebP/SDWebImageWebPCoder.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SDWebImage/WebP/SDWebImageWebPCoder.m b/SDWebImage/WebP/SDWebImageWebPCoder.m index 4ed071e0..9b25c5ce 100644 --- a/SDWebImage/WebP/SDWebImageWebPCoder.m +++ b/SDWebImage/WebP/SDWebImageWebPCoder.m @@ -12,6 +12,7 @@ #import "SDWebImageCoderHelper.h" #import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" +#import "UIImage+ForceDecode.h" #if __has_include() && __has_include() && __has_include() && __has_include() #import #import @@ -259,7 +260,7 @@ dispatch_semaphore_signal(self->_lock); // It will not keep memory barrier safe on x86 architechure (macOS & iPhone simulator) but on ARM architecture (iPhone & iPad & tv & watch) it works great // If different threads use WebPIDecGetRGB to grab rgba bitmap, it will contain the previous decoded bitmap data // So this will cause our drawed image looks strange(above is the current part but below is the previous part) - // We only grab the last_y height and draw the last_y heigh instead of total height image + // We only grab the last_y height and draw the last_y height instead of total height image // Besides fix, this can enhance performance since we do not need to create extra bitmap CGImageRef imageRef = CGImageCreate(width, last_y, 8, components * 8, components * width, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); @@ -296,6 +297,7 @@ dispatch_semaphore_signal(self->_lock); #else image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale orientation:kCGImagePropertyOrientationUp]; #endif + image.sd_isDecoded = YES; // Already drawn on bitmap context above CGImageRelease(newImageRef); CGContextRelease(canvas); } From 65537c4983aa3ff92cdf24978b440d66275efbbd Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 25 Apr 2018 14:21:38 +0800 Subject: [PATCH 164/361] Remove the check for URLProtocol in custom loader to avoid crash on iOS 8. Let URLSession itself or download operation to parse the result. --- SDWebImage/SDWebImageDownloader.m | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index f42568c2..1221bb63 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -469,23 +469,7 @@ didReceiveResponse:(NSURLResponse *)response if (!url) { return NO; } - Class operationClass = self.config.operationClass; - if (!operationClass || [operationClass isSubclassOfClass:[SDWebImageDownloaderOperation class]]) { - // Built-in download operation class, checking all supported NSURLProtocol - NSURLRequest *request = [NSURLRequest requestWithURL:url]; - NSArray *protocolClasses = self.sessionConfiguration.protocolClasses; - for (Class protocolClass in protocolClasses) { - if ([protocolClass isSubclassOfClass:[NSURLProtocol class]]) { - BOOL canLoad = [protocolClass canInitWithRequest:request]; - if (canLoad) { - return YES; - } - continue; - } - } - return NO; - } - // Custom download operation class may not dependent on NSURLSession, always pass YES. + // Always pass YES to let URLSession or custom download operation to determine return YES; } From 8f49d753b4e98d8d0b85ea3447c60e2d7b7aa485 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 25 Apr 2018 15:54:17 +0800 Subject: [PATCH 165/361] Remove the duplicated process to force decode (draw on bitmap context) in Image/IO's progressive decoding. This is the bug in early version of Image/IO framework, but now it's already been fixed and duplicated process impact performance --- SDWebImage/SDWebImageImageIOCoder.m | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index e35d2f7f..10c36666 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -150,25 +150,6 @@ // Create the image CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL); -#if SD_UIKIT || SD_WATCH - // Workaround for iOS anamorphic image - if (partialImageRef) { - const size_t partialHeight = CGImageGetHeight(partialImageRef); - CGColorSpaceRef colorSpace = [SDWebImageCoderHelper colorSpaceGetDeviceRGB]; - CGContextRef bmContext = CGBitmapContextCreate(NULL, _width, _height, 8, 0, colorSpace, kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst); - if (bmContext) { - CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = _width, .size.height = partialHeight}, partialImageRef); - CGImageRelease(partialImageRef); - partialImageRef = CGBitmapContextCreateImage(bmContext); - CGContextRelease(bmContext); - } - else { - CGImageRelease(partialImageRef); - partialImageRef = nil; - } - } -#endif - if (partialImageRef) { CGFloat scale = _scale; if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { From e9cf356e570e0641adbe60d61aa528d4f88cfc88 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 19 Apr 2018 22:27:28 +0800 Subject: [PATCH 166/361] Renaming `SDWebImageProgressiveDownload` to `SDWebImageProgressiveLoad`. Which is more suitable for custom loader which also support progressive image loading. (No need to be download) --- Examples/SDWebImage Demo/DetailViewController.m | 2 +- Examples/SDWebImage OSX Demo/ViewController.m | 2 +- SDWebImage/SDWebImageDefine.h | 4 ++-- SDWebImage/SDWebImageDownloader.h | 8 ++++---- SDWebImage/SDWebImageDownloader.m | 4 ++-- SDWebImage/SDWebImageDownloaderOperation.m | 2 +- SDWebImage/SDWebImageLoader.h | 2 +- SDWebImage/SDWebImageManager.h | 2 +- SDWebImage/UIView+WebCache.h | 2 +- Tests/Tests/SDAnimatedImageTest.m | 2 +- Tests/Tests/SDWebImageDownloaderTests.m | 4 ++-- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Examples/SDWebImage Demo/DetailViewController.m b/Examples/SDWebImage Demo/DetailViewController.m index a0c5ac22..e040e3d8 100644 --- a/Examples/SDWebImage Demo/DetailViewController.m +++ b/Examples/SDWebImage Demo/DetailViewController.m @@ -24,7 +24,7 @@ } [self.imageView sd_setImageWithURL:self.imageURL placeholderImage:nil - options:SDWebImageProgressiveDownload]; + options:SDWebImageProgressiveLoad]; } - (void)viewDidLoad diff --git a/Examples/SDWebImage OSX Demo/ViewController.m b/Examples/SDWebImage OSX Demo/ViewController.m index d709b46f..a510b978 100644 --- a/Examples/SDWebImage OSX Demo/ViewController.m +++ b/Examples/SDWebImage OSX Demo/ViewController.m @@ -29,7 +29,7 @@ self.imageView3.animates = YES; self.imageView4.animates = YES; self.imageView1.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator; - [self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"https://raw.githubusercontent.com/recurser/exif-orientation-examples/master/Landscape_2.jpg"] placeholderImage:nil options:SDWebImageProgressiveDownload]; + [self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"https://raw.githubusercontent.com/recurser/exif-orientation-examples/master/Landscape_2.jpg"] placeholderImage:nil options:SDWebImageProgressiveLoad]; [self.imageView2 sd_setImageWithURL:[NSURL URLWithString:@"https:raw.githubusercontent.com/onevcat/APNGKit/master/TestImages/APNG-cube.apng"]]; [self.imageView3 sd_setImageWithURL:[NSURL URLWithString:@"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"]]; self.imageView4.wantsLayer = YES; diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index c604ad80..7d274041 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -70,7 +70,7 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { * This flag enables progressive download, the image is displayed progressively during download as a browser would do. * By default, the image is only displayed once completely downloaded. */ - SDWebImageProgressiveDownload = 1 << 3, + SDWebImageProgressiveLoad = 1 << 3, /** * Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed. @@ -128,7 +128,7 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { /** * By default, images are decoded respecting their original size. On iOS, this flag will scale down the * images to a size compatible with the constrained memory of devices. - * This flag take no effect if `SDWebImageAvoidDecodeImage` is set. And it will be ignored if `SDWebImageProgressiveDownload` is set. + * This flag take no effect if `SDWebImageAvoidDecodeImage` is set. And it will be ignored if `SDWebImageProgressiveLoad` is set. */ SDWebImageScaleDownLargeImages = 1 << 12, diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index b5f428d8..441941d3 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -23,7 +23,7 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { /** * This flag enables progressive download, the image is displayed progressively during download as a browser would do. */ - SDWebImageDownloaderProgressiveDownload = 1 << 1, + SDWebImageDownloaderProgressiveLoad = 1 << 1, /** * By default, request prevent the use of NSURLCache. With this flag, NSURLCache @@ -64,7 +64,7 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { /** * By default, images are decoded respecting their original size. On iOS, this flag will scale down the * images to a size compatible with the constrained memory of devices. - * This flag take no effect if `SDWebImageDownloaderAvoidDecodeImage` is set. And it will be ignored if `SDWebImageDownloaderProgressiveDownload` is set. + * This flag take no effect if `SDWebImageDownloaderAvoidDecodeImage` is set. And it will be ignored if `SDWebImageDownloaderProgressiveLoad` is set. */ SDWebImageDownloaderScaleDownLargeImages = 1 << 8, @@ -197,8 +197,8 @@ typedef SDWebImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock; * @param completedBlock A block called once the download is completed. * If the download succeeded, the image parameter is set, in case of error, * error parameter is set with the error. The last parameter is always YES - * if SDWebImageDownloaderProgressiveDownload isn't use. With the - * SDWebImageDownloaderProgressiveDownload option, this block is called + * if SDWebImageDownloaderProgressiveLoad isn't use. With the + * SDWebImageDownloaderProgressiveLoad option, this block is called * repeatedly with the partial image object and the finished argument set to NO * before to be called a last time with the full image and finished argument * set to YES. In case of error, the finished argument is always YES. diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 1221bb63..bdfa21bf 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -480,7 +480,7 @@ didReceiveResponse:(NSURLResponse *)response } SDWebImageDownloaderOptions downloaderOptions = 0; if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority; - if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload; + if (options & SDWebImageProgressiveLoad) downloaderOptions |= SDWebImageDownloaderProgressiveLoad; if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache; if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground; if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies; @@ -490,7 +490,7 @@ didReceiveResponse:(NSURLResponse *)response if (cachedImage && options & SDWebImageRefreshCached) { // force progressive off if image already cached but forced refreshing - downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload; + downloaderOptions &= ~SDWebImageDownloaderProgressiveLoad; // ignore image read from NSURLCache if image if cached but force refreshing downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse; } diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 5a3dd465..7474f48f 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -335,7 +335,7 @@ didReceiveResponse:(NSURLResponse *)response } [self.imageData appendData:data]; - if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0) { + if ((self.options & SDWebImageDownloaderProgressiveLoad) && self.expectedSize > 0) { // Get the image data NSData *imageData = [self.imageData copy]; // Get the total bytes downloaded diff --git a/SDWebImage/SDWebImageLoader.h b/SDWebImage/SDWebImageLoader.h index 7ec47ac5..e0623b63 100644 --- a/SDWebImage/SDWebImageLoader.h +++ b/SDWebImage/SDWebImageLoader.h @@ -38,7 +38,7 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextLoader FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, SDWebImageOptions options, SDWebImageContext * _Nullable context); /** - This is the built-in decoding process for image progressive download from network. It's used when `SDWebImageProgressiveDownload` option is set. (It's not required when your loader does not support progressive image loading) + This is the built-in decoding process for image progressive download from network. It's used when `SDWebImageProgressiveLoad` option is set. (It's not required when your loader does not support progressive image loading) @note If you want to implement your custom loader with `loadImageWithURL:options:context:progress:completed:` API, but also want to keep compatible with SDWebImage's behavior, you'd better use this to produce image. @param imageData The image data from the network so far. Should not be nil diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 288f8473..8303d2ec 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -194,7 +194,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; * The forth parameter is an `SDImageCacheType` enum indicating if the image was retrieved from the local cache * or from the memory cache or from the network. * - * The fith parameter is set to NO when the SDWebImageProgressiveDownload option is used and the image is + * The fith parameter is set to NO when the SDWebImageProgressiveLoad option is used and the image is * downloading. This block is thus called repeatedly with a partial image. When image is fully downloaded, the * block is called a last time with the full image and the last parameter set to YES. * diff --git a/SDWebImage/UIView+WebCache.h b/SDWebImage/UIView+WebCache.h index a5f1046f..cf212146 100644 --- a/SDWebImage/UIView+WebCache.h +++ b/SDWebImage/UIView+WebCache.h @@ -59,7 +59,7 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima * The forth parameter is an `SDImageCacheType` enum indicating if the image was retrieved from the local cache * or from the memory cache or from the network. * - * The fith parameter normally is always YES. However, if you provide SDWebImageAvoidAutoSetImage with SDWebImageProgressiveDownload options to enable progressive downloading and set the image yourself. This block is thus called repeatedly with a partial image. When image is fully downloaded, the + * The fith parameter normally is always YES. However, if you provide SDWebImageAvoidAutoSetImage with SDWebImageProgressiveLoad options to enable progressive downloading and set the image yourself. This block is thus called repeatedly with a partial image. When image is fully downloaded, the * block is called a last time with the full image and the last parameter set to YES. * * The last parameter is the original image URL diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index 7c6907a0..6e995438 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -196,7 +196,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"]; SDAnimatedImageView *imageView = [SDAnimatedImageView new]; NSURL *testURL = [NSURL URLWithString:kTestGIFURL]; - [imageView sd_setImageWithURL:testURL placeholderImage:nil options:SDWebImageProgressiveDownload progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { + [imageView sd_setImageWithURL:testURL placeholderImage:nil options:SDWebImageProgressiveLoad progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { dispatch_async(dispatch_get_main_queue(), ^{ UIImage *image = imageView.image; // Progressive image may be nil when download data is not enough diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index fc7a70d9..916e96f8 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -136,7 +136,7 @@ - (void)test09ThatProgressiveJPEGWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Progressive JPEG download"]; NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; - [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:SDWebImageDownloaderProgressiveDownload progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:SDWebImageDownloaderProgressiveLoad progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { if (image && data && !error && finished) { [expectation fulfill]; } else if (finished) { @@ -251,7 +251,7 @@ - (void)test16ThatProgressiveWebPWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Progressive WebP download"]; NSURL *imageURL = [NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test9.webp"]; - [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:SDWebImageDownloaderProgressiveDownload progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:SDWebImageDownloaderProgressiveLoad progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { if (image && data && !error && finished) { [expectation fulfill]; } else if (finished) { From 425d78de12c711b33305e4fe9efd77fbdd8bb799 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 26 Apr 2018 21:48:34 +0800 Subject: [PATCH 167/361] Renaming the `downloadOperation` to `loaderOperation` in `SDWebImageCombinedOperation` --- SDWebImage/SDWebImageManager.h | 10 +++++----- SDWebImage/SDWebImageManager.m | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 8303d2ec..308625e6 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -19,23 +19,23 @@ typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _N typedef void(^SDInternalCompletionBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL); -// A combined operation representing the cache and download operation. You can it to cancel the load process. +// A combined operation representing the cache and loader operation. You can it to cancel the load process. @interface SDWebImageCombinedOperation : NSObject /** - Cancel the current operation, including cache and download process + Cancel the current operation, including cache and loader process */ - (void)cancel; /** - The cache operation used for image cache query + The cache operation from the image cache query */ @property (strong, nonatomic, nullable, readonly) id cacheOperation; /** - The download operation if the image is download from the network + The loader operation from the image loader (such as download operation) */ -@property (strong, nonatomic, nullable, readonly) id downloadOperation; +@property (strong, nonatomic, nullable, readonly) id loaderOperation; @end diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 92a7f470..23e9b93d 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -19,7 +19,7 @@ static id _defaultImageLoader; @interface SDWebImageCombinedOperation () @property (assign, nonatomic, getter = isCancelled) BOOL cancelled; -@property (strong, nonatomic, readwrite, nullable) id downloadOperation; +@property (strong, nonatomic, readwrite, nullable) id loaderOperation; @property (strong, nonatomic, readwrite, nullable) id cacheOperation; @property (weak, nonatomic, nullable) SDWebImageManager *manager; @@ -237,7 +237,7 @@ static id _defaultImageLoader; // `SDWebImageCombinedOperation` -> `SDWebImageDownloadToken` -> `downloadOperationCancelToken`, which is a `SDCallbacksDictionary` and retain the completed block below, so we need weak-strong again to avoid retain cycle __weak typeof(operation) weakOperation = operation; - operation.downloadOperation = [self.imageLoader loadImageWithURL:url options:options context:context progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { + operation.loaderOperation = [self.imageLoader loadImageWithURL:url options:options context:context progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { __strong typeof(weakOperation) strongOperation = weakOperation; if (!strongOperation || strongOperation.isCancelled) { // Do nothing if the operation was cancelled @@ -404,9 +404,9 @@ static id _defaultImageLoader; [self.cacheOperation cancel]; self.cacheOperation = nil; } - if (self.downloadOperation) { - [self.downloadOperation cancel]; - self.downloadOperation = nil; + if (self.loaderOperation) { + [self.loaderOperation cancel]; + self.loaderOperation = nil; } [self.manager safelyRemoveOperationFromRunning:self]; } From 189dc814f1eaeea63c30a631bf8cf30150a012ed Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 26 Apr 2018 22:08:03 +0800 Subject: [PATCH 168/361] Fix the test about HTTP Auth for downloader --- Tests/Tests/SDWebImageDownloaderTests.m | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index fc7a70d9..ae3ccda9 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -118,8 +118,10 @@ - (void)test08ThatAHTTPAuthDownloadWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"HTTP Auth download"]; - SDWebImageDownloader.sharedDownloader.config.username = @"httpwatch"; - SDWebImageDownloader.sharedDownloader.config.password = @"httpwatch01"; + SDWebImageDownloaderConfig *config = SDWebImageDownloaderConfig.defaultDownloaderConfig; + config.username = @"httpwatch"; + config.password = @"httpwatch01"; + SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] initWithConfig:config]; NSURL *imageURL = [NSURL URLWithString:@"http://www.httpwatch.com/httpgallery/authentication/authenticatedimage/default.aspx?0.35786508303135633"]; [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { if (image && data && !error && finished) { @@ -128,9 +130,9 @@ XCTFail(@"Something went wrong"); } }]; - [self waitForExpectationsWithCommonTimeout]; - SDWebImageDownloader.sharedDownloader.config.username = nil; - SDWebImageDownloader.sharedDownloader.config.password = nil; + [self waitForExpectationsWithCommonTimeoutUsingHandler:^(NSError * _Nullable error) { + [downloader invalidateSessionAndCancel:YES]; + }]; } - (void)test09ThatProgressiveJPEGWorks { From 5d7625f567d92a702630064e78f0a78574b77105 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 26 Apr 2018 23:02:45 +0800 Subject: [PATCH 169/361] Fix the HTTP auth test again --- Tests/Tests/SDWebImageDownloaderTests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index ae3ccda9..e83b93da 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -123,7 +123,7 @@ config.password = @"httpwatch01"; SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] initWithConfig:config]; NSURL *imageURL = [NSURL URLWithString:@"http://www.httpwatch.com/httpgallery/authentication/authenticatedimage/default.aspx?0.35786508303135633"]; - [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + [downloader downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { if (image && data && !error && finished) { [expectation fulfill]; } else { From e862ea1b8e7e0d10588bda4ea27eeaece1b59a1c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 26 Apr 2018 21:30:44 +0800 Subject: [PATCH 170/361] Rename all `SDWebImageTransformer` to `SDImageTransformer` --- SDWebImage.xcodeproj/project.pbxproj | 56 ++++++------ SDWebImage/SDImageCache.m | 6 +- ...mageTransformer.h => SDImageTransformer.h} | 26 +++--- ...mageTransformer.m => SDImageTransformer.m} | 90 +++++++++---------- SDWebImage/SDWebImageDefine.h | 4 +- SDWebImage/SDWebImageDefine.m | 2 +- SDWebImage/SDWebImageManager.h | 8 +- SDWebImage/SDWebImageManager.m | 8 +- WebImage/SDWebImage.h | 2 +- 9 files changed, 101 insertions(+), 101 deletions(-) rename SDWebImage/{SDWebImageTransformer.h => SDImageTransformer.h} (83%) rename SDWebImage/{SDWebImageTransformer.m => SDImageTransformer.m} (65%) diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index ec3e6d5b..6b67ea3b 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -559,18 +559,18 @@ 32F21B5A20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; 32F21B5B20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; 32F21B5C20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; }; - 32F7C06F2030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F7C0702030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F7C0712030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F7C0722030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F7C0732030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F7C0742030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32F7C0752030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; }; - 32F7C0762030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; }; - 32F7C0772030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; }; - 32F7C0782030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; }; - 32F7C0792030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; }; - 32F7C07A2030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; }; + 32F7C06F2030114C00873181 /* SDImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0702030114C00873181 /* SDImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0712030114C00873181 /* SDImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0722030114C00873181 /* SDImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0732030114C00873181 /* SDImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0742030114C00873181 /* SDImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32F7C0752030114C00873181 /* SDImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDImageTransformer.m */; }; + 32F7C0762030114C00873181 /* SDImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDImageTransformer.m */; }; + 32F7C0772030114C00873181 /* SDImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDImageTransformer.m */; }; + 32F7C0782030114C00873181 /* SDImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDImageTransformer.m */; }; + 32F7C0792030114C00873181 /* SDImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDImageTransformer.m */; }; + 32F7C07A2030114C00873181 /* SDImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDImageTransformer.m */; }; 32F7C07E2030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; 32F7C07F2030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; 32F7C0802030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; }; @@ -1630,8 +1630,8 @@ 32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageCachesManager.h; sourceTree = ""; }; 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderRequestModifier.h; sourceTree = ""; }; 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderRequestModifier.m; sourceTree = ""; }; - 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTransformer.h; sourceTree = ""; }; - 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransformer.m; sourceTree = ""; }; + 32F7C06D2030114C00873181 /* SDImageTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageTransformer.h; sourceTree = ""; }; + 32F7C06E2030114C00873181 /* SDImageTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageTransformer.m; sourceTree = ""; }; 32F7C07C2030719600873181 /* UIImage+Transform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Transform.m"; sourceTree = ""; }; 32F7C07D2030719600873181 /* UIImage+Transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Transform.h"; sourceTree = ""; }; 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MKAnnotationView+WebCache.m"; sourceTree = ""; }; @@ -1976,8 +1976,8 @@ 328BB6992081FDDF00760D6C /* Transformer */ = { isa = PBXGroup; children = ( - 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */, - 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */, + 32F7C06D2030114C00873181 /* SDImageTransformer.h */, + 32F7C06E2030114C00873181 /* SDImageTransformer.m */, ); name = Transformer; sourceTree = ""; @@ -2474,7 +2474,7 @@ 32C0FDE42013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 321E60C11F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 80377DBE1F2F66A700F89830 /* dsp.h in Headers */, - 32F7C0722030114C00873181 /* SDWebImageTransformer.h in Headers */, + 32F7C0722030114C00873181 /* SDImageTransformer.h in Headers */, 80377EB81F2F66D400F89830 /* alphai_dec.h in Headers */, 00733A6D1BC4880E00A5A117 /* UIImage+GIF.h in Headers */, 80377C551F2F666300F89830 /* quant_levels_dec_utils.h in Headers */, @@ -2506,7 +2506,7 @@ 80377C141F2F666300F89830 /* bit_reader_utils.h in Headers */, 328BB69D2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, 323F8C0F1F38EF770092B609 /* muxi.h in Headers */, - 32F7C0702030114C00873181 /* SDWebImageTransformer.h in Headers */, + 32F7C0702030114C00873181 /* SDImageTransformer.h in Headers */, 80377C2B1F2F666300F89830 /* utils.h in Headers */, 4314D1621D0E0E3B004B36C9 /* mux_types.h in Headers */, 4314D1631D0E0E3B004B36C9 /* demux.h in Headers */, @@ -2665,7 +2665,7 @@ 807A122C1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, 323F8BFA1F38EF770092B609 /* animi.h in Headers */, 431BB6F91D06D2C1006A3455 /* UIImage+GIF.h in Headers */, - 32F7C0732030114C00873181 /* SDWebImageTransformer.h in Headers */, + 32F7C0732030114C00873181 /* SDImageTransformer.h in Headers */, 431BB6FA1D06D2C1006A3455 /* SDWebImageDownloader.h in Headers */, 3248476D201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 32D122222080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, @@ -2734,7 +2734,7 @@ 32CF1C0C1FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, 43A918691D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 4397D2D81D0DDD8C00BB2784 /* UIButton+WebCache.h in Headers */, - 32F7C0742030114C00873181 /* SDWebImageTransformer.h in Headers */, + 32F7C0742030114C00873181 /* SDImageTransformer.h in Headers */, 80377E641F2F66A800F89830 /* mips_macro.h in Headers */, 328BB6D22082581100760D6C /* SDMemoryCache.h in Headers */, 323F8BDD1F38EF770092B609 /* vp8i_enc.h in Headers */, @@ -2870,7 +2870,7 @@ 32C0FDE32013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 80377D791F2F66A700F89830 /* dsp.h in Headers */, 80377EA81F2F66D400F89830 /* alphai_dec.h in Headers */, - 32F7C0712030114C00873181 /* SDWebImageTransformer.h in Headers */, + 32F7C0712030114C00873181 /* SDImageTransformer.h in Headers */, 4A2CAE2D1AB4BB7500B6BC39 /* UIImage+GIF.h in Headers */, 80377C3B1F2F666300F89830 /* quant_levels_dec_utils.h in Headers */, 80377EB11F2F66D400F89830 /* vp8_dec.h in Headers */, @@ -2930,7 +2930,7 @@ 32FDE8802088871B008D7530 /* MKAnnotationView+WebCache.h in Headers */, 321E60BE1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 5376131E155AD0D5005750A4 /* SDWebImagePrefetcher.h in Headers */, - 32F7C06F2030114C00873181 /* SDWebImageTransformer.h in Headers */, + 32F7C06F2030114C00873181 /* SDImageTransformer.h in Headers */, 321B378D2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, 32FDE8A220888789008D7530 /* SDWebImage.h in Headers */, 324DF4B4200A14DC008A84CC /* SDWebImageDefine.h in Headers */, @@ -3233,7 +3233,7 @@ 323F8B7D1F38EF770092B609 /* frame_enc.c in Sources */, 328BB6D62082581100760D6C /* SDMemoryCache.m in Sources */, 80377EBB1F2F66D500F89830 /* frame_dec.c in Sources */, - 32F7C0782030114C00873181 /* SDWebImageTransformer.m in Sources */, + 32F7C0782030114C00873181 /* SDImageTransformer.m in Sources */, 80377DAF1F2F66A700F89830 /* argb.c in Sources */, 323F8B6B1F38EF770092B609 /* delta_palettization_enc.c in Sources */, 00733A5B1BC4880000A5A117 /* NSData+ImageContentType.m in Sources */, @@ -3479,7 +3479,7 @@ 4314D1411D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.m in Sources */, 80377D561F2F66A700F89830 /* rescaler_neon.c in Sources */, 32B9B53E206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, - 32F7C0762030114C00873181 /* SDWebImageTransformer.m in Sources */, + 32F7C0762030114C00873181 /* SDImageTransformer.m in Sources */, 80377D551F2F66A700F89830 /* rescaler_msa.c in Sources */, 80377D5E1F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */, 80377D611F2F66A700F89830 /* yuv.c in Sources */, @@ -3645,7 +3645,7 @@ 3237F9EA20161AE000A88143 /* NSImage+Compatibility.m in Sources */, 80377E251F2F66A800F89830 /* rescaler_neon.c in Sources */, 32B9B541206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, - 32F7C0792030114C00873181 /* SDWebImageTransformer.m in Sources */, + 32F7C0792030114C00873181 /* SDImageTransformer.m in Sources */, 80377E241F2F66A800F89830 /* rescaler_msa.c in Sources */, 80377E2D1F2F66A800F89830 /* yuv_mips_dsp_r2.c in Sources */, 431BB6B91D06D2C1006A3455 /* UIButton+WebCache.m in Sources */, @@ -3858,7 +3858,7 @@ 80377EE51F2F66D500F89830 /* webp_dec.c in Sources */, 4397D2B01D0DDD8C00BB2784 /* SDImageCache.m in Sources */, 321B37982083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */, - 32F7C07A2030114C00873181 /* SDWebImageTransformer.m in Sources */, + 32F7C07A2030114C00873181 /* SDImageTransformer.m in Sources */, 80377E4F1F2F66A800F89830 /* enc_sse41.c in Sources */, 80377E701F2F66A800F89830 /* upsampling_sse2.c in Sources */, ); @@ -3902,7 +3902,7 @@ 323F8B7C1F38EF770092B609 /* frame_enc.c in Sources */, 328BB6D52082581100760D6C /* SDMemoryCache.m in Sources */, 80377EAB1F2F66D400F89830 /* frame_dec.c in Sources */, - 32F7C0772030114C00873181 /* SDWebImageTransformer.m in Sources */, + 32F7C0772030114C00873181 /* SDImageTransformer.m in Sources */, 43C8929D1D9D6DD90022038D /* anim_decode.c in Sources */, 323F8B6A1F38EF770092B609 /* delta_palettization_enc.c in Sources */, 43CE75D41CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */, @@ -4073,7 +4073,7 @@ 80377E8B1F2F66D000F89830 /* frame_dec.c in Sources */, 328BB6D32082581100760D6C /* SDMemoryCache.m in Sources */, 43C8929A1D9D6DD70022038D /* anim_decode.c in Sources */, - 32F7C0752030114C00873181 /* SDWebImageTransformer.m in Sources */, + 32F7C0752030114C00873181 /* SDImageTransformer.m in Sources */, 323F8B681F38EF770092B609 /* delta_palettization_enc.c in Sources */, 43CE75D31CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */, 323F8B5C1F38EF770092B609 /* cost_enc.c in Sources */, diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 175256ff..862b90c5 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -12,7 +12,7 @@ #import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" #import "SDWebImageCodersManager.h" -#import "SDWebImageTransformer.h" +#import "SDImageTransformer.h" #import "SDWebImageCoderHelper.h" #import "SDAnimatedImage.h" @@ -371,9 +371,9 @@ cacheType = SDImageCacheTypeMemory; } else if (diskData) { NSString *cacheKey = key; - if ([context valueForKey:SDWebImageContextCustomTransformer]) { + if ([context valueForKey:SDWebImageContextImageTransformer]) { // grab the transformed disk image if transformer provided - id transformer = [context valueForKey:SDWebImageContextCustomTransformer]; + id transformer = [context valueForKey:SDWebImageContextImageTransformer]; NSString *transformerKey = [transformer transformerKey]; cacheKey = SDTransformedKeyForKey(key, transformerKey); } diff --git a/SDWebImage/SDWebImageTransformer.h b/SDWebImage/SDImageTransformer.h similarity index 83% rename from SDWebImage/SDWebImageTransformer.h rename to SDWebImage/SDImageTransformer.h index 31c126d7..a3e834ce 100644 --- a/SDWebImage/SDWebImageTransformer.h +++ b/SDWebImage/SDImageTransformer.h @@ -20,11 +20,11 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab /** A transformer protocol to transform the image load from cache or from download. - You can provide transformer to cache and manager (Through the `transformer` property or context option `SDWebImageContextCustomTransformer`). + You can provide transformer to cache and manager (Through the `transformer` property or context option `SDWebImageContextImageTransformer`). @note The transform process is called from a global queue in order to not to block the main queue. */ -@protocol SDWebImageTransformer +@protocol SDImageTransformer @required /** @@ -49,12 +49,12 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab // Pipeline transformer. Which you can bind multiple transformers together to let the image to be transformed one by one in order and generate the final image. // Because transformers are lightweight, if you want to append or arrange transfomers, create another pipeline transformer instead. This class is considered as immutable. -@interface SDWebImagePipelineTransformer : NSObject +@interface SDImagePipelineTransformer : NSObject -@property (nonatomic, copy, readonly, nonnull) NSArray> *transformers; +@property (nonatomic, copy, readonly, nonnull) NSArray> *transformers; - (nonnull instancetype)init NS_UNAVAILABLE; -+ (nonnull instancetype)transformerWithTransformers:(nonnull NSArray> *)transformers; ++ (nonnull instancetype)transformerWithTransformers:(nonnull NSArray> *)transformers; @end @@ -63,7 +63,7 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab #pragma mark - Image Geometry // Image round corner transformer -@interface SDWebImageRoundCornerTransformer: NSObject +@interface SDImageRoundCornerTransformer: NSObject @property (nonatomic, assign, readonly) CGFloat cornerRadius; @property (nonatomic, assign, readonly) SDRectCorner corners; @@ -76,7 +76,7 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab @end // Image resizing transformer -@interface SDWebImageResizingTransformer : NSObject +@interface SDImageResizingTransformer : NSObject @property (nonatomic, assign, readonly) CGSize size; @property (nonatomic, assign, readonly) SDImageScaleMode scaleMode; @@ -87,7 +87,7 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab @end // Image cropping transformer -@interface SDWebImageCroppingTransformer : NSObject +@interface SDImageCroppingTransformer : NSObject @property (nonatomic, assign, readonly) CGRect rect; @@ -97,7 +97,7 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab @end // Image flipping transformer -@interface SDWebImageFlippingTransformer : NSObject +@interface SDImageFlippingTransformer : NSObject @property (nonatomic, assign, readonly) BOOL horizontal; @property (nonatomic, assign, readonly) BOOL vertical; @@ -108,7 +108,7 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab @end // Image rotation transformer -@interface SDWebImageRotationTransformer : NSObject +@interface SDImageRotationTransformer : NSObject @property (nonatomic, assign, readonly) CGFloat angle; @property (nonatomic, assign, readonly) BOOL fitSize; @@ -121,7 +121,7 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab #pragma mark - Image Blending // Image tint color transformer -@interface SDWebImageTintTransformer : NSObject +@interface SDImageTintTransformer : NSObject @property (nonatomic, strong, readonly, nonnull) UIColor *tintColor; @@ -133,7 +133,7 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab #pragma mark - Image Effect // Image blur effect transformer -@interface SDWebImageBlurTransformer : NSObject +@interface SDImageBlurTransformer : NSObject @property (nonatomic, assign, readonly) CGFloat blurRadius; @@ -144,7 +144,7 @@ FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullab #if SD_UIKIT || SD_MAC // Core Image filter transformer -@interface SDWebImageFilterTransformer: NSObject +@interface SDImageFilterTransformer: NSObject @property (nonatomic, strong, readonly, nonnull) CIFilter *filter; diff --git a/SDWebImage/SDWebImageTransformer.m b/SDWebImage/SDImageTransformer.m similarity index 65% rename from SDWebImage/SDWebImageTransformer.m rename to SDWebImage/SDImageTransformer.m index 740ff09e..0b0b58d7 100644 --- a/SDWebImage/SDWebImageTransformer.m +++ b/SDWebImage/SDImageTransformer.m @@ -6,19 +6,19 @@ * file that was distributed with this source code. */ -#import "SDWebImageTransformer.h" +#import "SDImageTransformer.h" #if SD_UIKIT || SD_MAC #import #endif -// Separator for different transformerKey, for example, `image.png` |> flip(YES,NO) |> rotate(pi/4,YES) => 'image-SDWebImageFlippingTransformer(1,0)-SDWebImageRotationTransformer(0.78539816339,1).png' -static NSString * const SDWebImageTransformerKeySeparator = @"-"; +// Separator for different transformerKey, for example, `image.png` |> flip(YES,NO) |> rotate(pi/4,YES) => 'image-SDImageFlippingTransformer(1,0)-SDImageRotationTransformer(0.78539816339,1).png' +static NSString * const SDImageTransformerKeySeparator = @"-"; NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * _Nonnull transformerKey) { if (!key || !transformerKey) { return nil; } - return [[key stringByAppendingString:SDWebImageTransformerKeySeparator] stringByAppendingString:transformerKey]; + return [[key stringByAppendingString:SDImageTransformerKeySeparator] stringByAppendingString:transformerKey]; } @interface UIColor (HexString) @@ -63,34 +63,34 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * @end -@interface SDWebImagePipelineTransformer () +@interface SDImagePipelineTransformer () -@property (nonatomic, copy, readwrite, nonnull) NSArray> *transformers; +@property (nonatomic, copy, readwrite, nonnull) NSArray> *transformers; @property (nonatomic, copy, readwrite) NSString *transformerKey; @end -@implementation SDWebImagePipelineTransformer +@implementation SDImagePipelineTransformer -+ (instancetype)transformerWithTransformers:(NSArray> *)transformers { - SDWebImagePipelineTransformer *transformer = [SDWebImagePipelineTransformer new]; ++ (instancetype)transformerWithTransformers:(NSArray> *)transformers { + SDImagePipelineTransformer *transformer = [SDImagePipelineTransformer new]; transformer.transformers = transformers; transformer.transformerKey = [[self class] cacheKeyForTransformers:transformers]; return transformer; } -+ (NSString *)cacheKeyForTransformers:(NSArray> *)transformers { ++ (NSString *)cacheKeyForTransformers:(NSArray> *)transformers { if (transformers.count == 0) { return @""; } NSMutableArray *cacheKeys = [NSMutableArray arrayWithCapacity:transformers.count]; - [transformers enumerateObjectsUsingBlock:^(id _Nonnull transformer, NSUInteger idx, BOOL * _Nonnull stop) { + [transformers enumerateObjectsUsingBlock:^(id _Nonnull transformer, NSUInteger idx, BOOL * _Nonnull stop) { NSString *cacheKey = transformer.transformerKey; [cacheKeys addObject:cacheKey]; }]; - return [cacheKeys componentsJoinedByString:SDWebImageTransformerKeySeparator]; + return [cacheKeys componentsJoinedByString:SDImageTransformerKeySeparator]; } - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { @@ -98,7 +98,7 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * return nil; } UIImage *transformedImage = image; - for (id transformer in self.transformers) { + for (id transformer in self.transformers) { transformedImage = [transformer transformedImageWithImage:transformedImage forKey:key]; } return transformedImage; @@ -106,7 +106,7 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * @end -@interface SDWebImageRoundCornerTransformer () +@interface SDImageRoundCornerTransformer () @property (nonatomic, assign) CGFloat cornerRadius; @property (nonatomic, assign) SDRectCorner corners; @@ -115,10 +115,10 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * @end -@implementation SDWebImageRoundCornerTransformer +@implementation SDImageRoundCornerTransformer + (instancetype)transformerWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor { - SDWebImageRoundCornerTransformer *transformer = [SDWebImageRoundCornerTransformer new]; + SDImageRoundCornerTransformer *transformer = [SDImageRoundCornerTransformer new]; transformer.cornerRadius = cornerRadius; transformer.corners = corners; transformer.borderWidth = borderWidth; @@ -128,7 +128,7 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * } - (NSString *)transformerKey { - return [NSString stringWithFormat:@"SDWebImageRoundCornerTransformer(%f,%lu,%f,%@)", self.cornerRadius, (unsigned long)self.corners, self.borderWidth, self.borderColor.sd_hexString]; + return [NSString stringWithFormat:@"SDImageRoundCornerTransformer(%f,%lu,%f,%@)", self.cornerRadius, (unsigned long)self.corners, self.borderWidth, self.borderColor.sd_hexString]; } - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { @@ -140,17 +140,17 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * @end -@interface SDWebImageResizingTransformer () +@interface SDImageResizingTransformer () @property (nonatomic, assign) CGSize size; @property (nonatomic, assign) SDImageScaleMode scaleMode; @end -@implementation SDWebImageResizingTransformer +@implementation SDImageResizingTransformer + (instancetype)transformerWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode { - SDWebImageResizingTransformer *transformer = [SDWebImageResizingTransformer new]; + SDImageResizingTransformer *transformer = [SDImageResizingTransformer new]; transformer.size = size; transformer.scaleMode = scaleMode; @@ -159,7 +159,7 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * - (NSString *)transformerKey { CGSize size = self.size; - return [NSString stringWithFormat:@"SDWebImageResizingTransformer({%f,%f},%lu)", size.width, size.height, (unsigned long)self.scaleMode]; + return [NSString stringWithFormat:@"SDImageResizingTransformer({%f,%f},%lu)", size.width, size.height, (unsigned long)self.scaleMode]; } - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { @@ -171,16 +171,16 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * @end -@interface SDWebImageCroppingTransformer () +@interface SDImageCroppingTransformer () @property (nonatomic, assign) CGRect rect; @end -@implementation SDWebImageCroppingTransformer +@implementation SDImageCroppingTransformer + (instancetype)transformerWithRect:(CGRect)rect { - SDWebImageCroppingTransformer *transformer = [SDWebImageCroppingTransformer new]; + SDImageCroppingTransformer *transformer = [SDImageCroppingTransformer new]; transformer.rect = rect; return transformer; @@ -188,7 +188,7 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * - (NSString *)transformerKey { CGRect rect = self.rect; - return [NSString stringWithFormat:@"SDWebImageCroppingTransformer({%f,%f,%f,%f})", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height]; + return [NSString stringWithFormat:@"SDImageCroppingTransformer({%f,%f,%f,%f})", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height]; } - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { @@ -200,17 +200,17 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * @end -@interface SDWebImageFlippingTransformer () +@interface SDImageFlippingTransformer () @property (nonatomic, assign) BOOL horizontal; @property (nonatomic, assign) BOOL vertical; @end -@implementation SDWebImageFlippingTransformer +@implementation SDImageFlippingTransformer + (instancetype)transformerWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical { - SDWebImageFlippingTransformer *transformer = [SDWebImageFlippingTransformer new]; + SDImageFlippingTransformer *transformer = [SDImageFlippingTransformer new]; transformer.horizontal = horizontal; transformer.vertical = vertical; @@ -218,7 +218,7 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * } - (NSString *)transformerKey { - return [NSString stringWithFormat:@"SDWebImageFlippingTransformer(%d,%d)", self.horizontal, self.vertical]; + return [NSString stringWithFormat:@"SDImageFlippingTransformer(%d,%d)", self.horizontal, self.vertical]; } - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { @@ -230,17 +230,17 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * @end -@interface SDWebImageRotationTransformer () +@interface SDImageRotationTransformer () @property (nonatomic, assign) CGFloat angle; @property (nonatomic, assign) BOOL fitSize; @end -@implementation SDWebImageRotationTransformer +@implementation SDImageRotationTransformer + (instancetype)transformerWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize { - SDWebImageRotationTransformer *transformer = [SDWebImageRotationTransformer new]; + SDImageRotationTransformer *transformer = [SDImageRotationTransformer new]; transformer.angle = angle; transformer.fitSize = fitSize; @@ -248,7 +248,7 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * } - (NSString *)transformerKey { - return [NSString stringWithFormat:@"SDWebImageRotationTransformer(%f,%d)", self.angle, self.fitSize]; + return [NSString stringWithFormat:@"SDImageRotationTransformer(%f,%d)", self.angle, self.fitSize]; } - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { @@ -262,23 +262,23 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * #pragma mark - Image Blending -@interface SDWebImageTintTransformer () +@interface SDImageTintTransformer () @property (nonatomic, strong, nonnull) UIColor *tintColor; @end -@implementation SDWebImageTintTransformer +@implementation SDImageTintTransformer + (instancetype)transformerWithColor:(UIColor *)tintColor { - SDWebImageTintTransformer *transformer = [SDWebImageTintTransformer new]; + SDImageTintTransformer *transformer = [SDImageTintTransformer new]; transformer.tintColor = tintColor; return transformer; } - (NSString *)transformerKey { - return [NSString stringWithFormat:@"SDWebImageTintTransformer(%@)", self.tintColor.sd_hexString]; + return [NSString stringWithFormat:@"SDImageTintTransformer(%@)", self.tintColor.sd_hexString]; } - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { @@ -292,23 +292,23 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * #pragma mark - Image Effect -@interface SDWebImageBlurTransformer () +@interface SDImageBlurTransformer () @property (nonatomic, assign) CGFloat blurRadius; @end -@implementation SDWebImageBlurTransformer +@implementation SDImageBlurTransformer + (instancetype)transformerWithRadius:(CGFloat)blurRadius { - SDWebImageBlurTransformer *transformer = [SDWebImageBlurTransformer new]; + SDImageBlurTransformer *transformer = [SDImageBlurTransformer new]; transformer.blurRadius = blurRadius; return transformer; } - (NSString *)transformerKey { - return [NSString stringWithFormat:@"SDWebImageBlurTransformer(%f)", self.blurRadius]; + return [NSString stringWithFormat:@"SDImageBlurTransformer(%f)", self.blurRadius]; } - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { @@ -321,23 +321,23 @@ NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * @end #if SD_UIKIT || SD_MAC -@interface SDWebImageFilterTransformer () +@interface SDImageFilterTransformer () @property (nonatomic, strong, nonnull) CIFilter *filter; @end -@implementation SDWebImageFilterTransformer +@implementation SDImageFilterTransformer + (instancetype)transformerWithFilter:(CIFilter *)filter { - SDWebImageFilterTransformer *transformer = [SDWebImageFilterTransformer new]; + SDImageFilterTransformer *transformer = [SDImageFilterTransformer new]; transformer.filter = filter; return transformer; } - (NSString *)transformerKey { - return [NSString stringWithFormat:@"SDWebImageFilterTransformer(%@)", self.filter.name]; + return [NSString stringWithFormat:@"SDImageFilterTransformer(%@)", self.filter.name]; } - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key { diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index c604ad80..4e905451 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -196,9 +196,9 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextSetIma FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustomManager; /** - A id instance which conforms SDWebImageTransformer protocol. It's used for image transform after the image load finished and store the transformed image to cache. If you provide one, it will ignore the `transformer` in manager and use provided one instead. (id) + A id instance which conforms `SDImageTransformer` protocol. It's used for image transform after the image load finished and store the transformed image to cache. If you provide one, it will ignore the `transformer` in manager and use provided one instead. (id) */ -FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustomTransformer; +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageTransformer; /** A CGFloat value which specify the image scale factor. The number should be greater than or equal to 1.0. If not provide or the number is invalid, we will use the cache key to specify the scale factor. (NSNumber) diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m index 0f386021..21bc081a 100644 --- a/SDWebImage/SDWebImageDefine.m +++ b/SDWebImage/SDWebImageDefine.m @@ -119,7 +119,7 @@ inline UIImage * _Nullable SDScaledImageForScaleFactor(CGFloat scale, UIImage * SDWebImageContextOption const SDWebImageContextSetImageOperationKey = @"setImageOperationKey"; SDWebImageContextOption const SDWebImageContextSetImageGroup = @"setImageGroup"; SDWebImageContextOption const SDWebImageContextCustomManager = @"customManager"; -SDWebImageContextOption const SDWebImageContextCustomTransformer = @"customTransformer"; +SDWebImageContextOption const SDWebImageContextImageTransformer = @"imageTransformer"; SDWebImageContextOption const SDWebImageContextImageScaleFactor = @"imageScaleFactor"; SDWebImageContextOption const SDWebImageContextAnimatedImageClass = @"animatedImageClass"; SDWebImageContextOption const SDWebImageContextDownloadRequestModifier = @"downloadRequestModifier"; diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 288f8473..f1e81f45 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -10,7 +10,7 @@ #import "SDWebImageOperation.h" #import "SDImageCacheDefine.h" #import "SDWebImageDownloader.h" -#import "SDWebImageTransformer.h" +#import "SDImageTransformer.h" #import "SDWebImageCacheKeyFilter.h" #import "SDWebImageCacheSerializer.h" #import "SDWebImageLoader.h" @@ -108,11 +108,11 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; @property (strong, nonatomic, readonly, nonnull) id imageLoader; /** - The image transformer for manager. It's used for image transform after the image load finished and store the transformed image to cache, see `SDWebImageTransformer`. + The image transformer for manager. It's used for image transform after the image load finished and store the transformed image to cache, see `SDImageTransformer`. Defaults to nil, which means no transform is applied. - @note This will affect all the load requests for this manager if you provide. However, you can pass `SDWebImageContextCustomTransformer` in context arg to explicitly use that transformer instead. + @note This will affect all the load requests for this manager if you provide. However, you can pass `SDWebImageContextImageTransformer` in context arg to explicitly use that transformer instead. */ -@property (strong, nonatomic, nullable) id transformer; +@property (strong, nonatomic, nullable) id transformer; /** * The cache filter is used to convert an URL into a cache key each time SDWebImageManager need cache key to use image cache. diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 92a7f470..a4581f58 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -280,7 +280,7 @@ static id _defaultImageLoader; } id cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter]; NSString *key = [self cacheKeyForURL:url cacheKeyFilter:cacheKeyFilter]; - id transformer = [context valueForKey:SDWebImageContextCustomTransformer]; + id transformer = [context valueForKey:SDWebImageContextImageTransformer]; id cacheSerializer = [context valueForKey:SDWebImageContextCacheKeyFilter]; if (downloadedImage && (!downloadedImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage)) && transformer) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ @@ -366,9 +366,9 @@ static id _defaultImageLoader; SDWebImageMutableContext *mutableContext = [SDWebImageMutableContext dictionary]; // Image Transformer from manager - if (![context valueForKey:SDWebImageContextCustomTransformer]) { - id transformer = self.transformer; - [mutableContext setValue:transformer forKey:SDWebImageContextCustomTransformer]; + if (![context valueForKey:SDWebImageContextImageTransformer]) { + id transformer = self.transformer; + [mutableContext setValue:transformer forKey:SDWebImageContextImageTransformer]; } // Cache key filter from manager if (![context valueForKey:SDWebImageContextCacheKeyFilter]) { diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index ed37b422..1cb1ebc9 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -47,7 +47,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import -#import +#import #import #import #import From a5616e2bcd92216d0f5f25d479cea7909e68deb0 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 26 Apr 2018 21:36:25 +0800 Subject: [PATCH 171/361] Update the test for renaming --- Tests/SDWebImage Tests.xcodeproj/project.pbxproj | 12 ++++++------ ...ransformerTests.m => SDImageTransformerTests.m} | 14 +++++++------- Tests/Tests/SDWebImageTestTransformer.h | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) rename Tests/Tests/{SDWebImageTransformerTests.m => SDImageTransformerTests.m} (90%) diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 63e363f3..1a264a90 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -17,8 +17,8 @@ 3226ECBC20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */; }; 323B8E1F20862322008952BE /* SDWebImageTestLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 323B8E1E20862322008952BE /* SDWebImageTestLoader.m */; }; 323B8E2020862322008952BE /* SDWebImageTestLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 323B8E1E20862322008952BE /* SDWebImageTestLoader.m */; }; - 3254C32020641077008D1022 /* SDWebImageTransformerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */; }; - 3254C32120641077008D1022 /* SDWebImageTransformerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */; }; + 3254C32020641077008D1022 /* SDImageTransformerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3254C31F20641077008D1022 /* SDImageTransformerTests.m */; }; + 3254C32120641077008D1022 /* SDImageTransformerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3254C31F20641077008D1022 /* SDImageTransformerTests.m */; }; 3264FF2F205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */; }; 3264FF30205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */; }; 327054E2206CEFF3006EA328 /* TestImageAnimated.apng in Resources */ = {isa = PBXBuildFile; fileRef = 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */; }; @@ -74,7 +74,7 @@ 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestDownloadOperation.m; sourceTree = ""; }; 323B8E1D20862322008952BE /* SDWebImageTestLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestLoader.h; sourceTree = ""; }; 323B8E1E20862322008952BE /* SDWebImageTestLoader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestLoader.m; sourceTree = ""; }; - 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransformerTests.m; sourceTree = ""; }; + 3254C31F20641077008D1022 /* SDImageTransformerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageTransformerTests.m; sourceTree = ""; }; 3264FF2D205D42CB00F6BD48 /* SDWebImageTestTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestTransformer.h; sourceTree = ""; }; 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestTransformer.m; sourceTree = ""; }; 327054E1206CEFF3006EA328 /* TestImageAnimated.apng */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageAnimated.apng; sourceTree = ""; }; @@ -211,7 +211,7 @@ 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */, 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */, 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */, - 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */, + 3254C31F20641077008D1022 /* SDImageTransformerTests.m */, 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */, 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */, 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */, @@ -478,7 +478,7 @@ files = ( 323B8E2020862322008952BE /* SDWebImageTestLoader.m in Sources */, 32B99EAC203B36650017FD66 /* SDWebImageDownloaderTests.m in Sources */, - 3254C32120641077008D1022 /* SDWebImageTransformerTests.m in Sources */, + 3254C32120641077008D1022 /* SDImageTransformerTests.m in Sources */, 328BB6DE20825E9800760D6C /* SDWebImageTestCache.m in Sources */, 32B99E9C203B2EE40017FD66 /* SDCategoriesTests.m in Sources */, 32B99EAA203B365F0017FD66 /* SDImageCacheTests.m in Sources */, @@ -502,7 +502,7 @@ 323B8E1F20862322008952BE /* SDWebImageTestLoader.m in Sources */, 32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */, 3226ECBB20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */, - 3254C32020641077008D1022 /* SDWebImageTransformerTests.m in Sources */, + 3254C32020641077008D1022 /* SDImageTransformerTests.m in Sources */, 32A571562037DB2D002EDAAE /* SDAnimatedImageTest.m in Sources */, 1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */, 37D122881EC48B5E00D98CEB /* SDMockFileManager.m in Sources */, diff --git a/Tests/Tests/SDWebImageTransformerTests.m b/Tests/Tests/SDImageTransformerTests.m similarity index 90% rename from Tests/Tests/SDWebImageTransformerTests.m rename to Tests/Tests/SDImageTransformerTests.m index 155a70b1..105be68e 100644 --- a/Tests/Tests/SDWebImageTransformerTests.m +++ b/Tests/Tests/SDImageTransformerTests.m @@ -17,13 +17,13 @@ @end -@interface SDWebImageTransformerTests : SDTestCase +@interface SDImageTransformerTests : SDTestCase @property (nonatomic, strong) UIImage *testImage; @end -@implementation SDWebImageTransformerTests +@implementation SDImageTransformerTests #pragma mark - UIImage+Transform @@ -125,7 +125,7 @@ expect([leftColor.sd_hexString isEqualToString:expectedColor.sd_hexString]); } -#pragma mark - SDWebImageTransformer +#pragma mark - SDImageTransformer - (void)test09ImagePipelineTransformer { CGSize size = CGSizeMake(100, 100); @@ -140,10 +140,10 @@ #endif CGFloat borderWidth = 1; UIColor *borderCoder = [UIColor blackColor]; - SDWebImageResizingTransformer *transformer1 = [SDWebImageResizingTransformer transformerWithSize:size scaleMode:scaleMode]; - SDWebImageRotationTransformer *transformer2 = [SDWebImageRotationTransformer transformerWithAngle:angle fitSize:fitSize]; - SDWebImageRoundCornerTransformer *transformer3 = [SDWebImageRoundCornerTransformer transformerWithRadius:radius corners:corners borderWidth:borderWidth borderColor:borderCoder]; - SDWebImagePipelineTransformer *pipelineTransformer = [SDWebImagePipelineTransformer transformerWithTransformers:@[transformer1, transformer2, transformer3]]; + SDImageResizingTransformer *transformer1 = [SDImageResizingTransformer transformerWithSize:size scaleMode:scaleMode]; + SDImageRotationTransformer *transformer2 = [SDImageRotationTransformer transformerWithAngle:angle fitSize:fitSize]; + SDImageRoundCornerTransformer *transformer3 = [SDImageRoundCornerTransformer transformerWithRadius:radius corners:corners borderWidth:borderWidth borderColor:borderCoder]; + SDImagePipelineTransformer *pipelineTransformer = [SDImagePipelineTransformer transformerWithTransformers:@[transformer1, transformer2, transformer3]]; UIImage *transformedImage = [pipelineTransformer transformedImageWithImage:self.testImage forKey:@"Test"]; expect(CGSizeEqualToSize(transformedImage.size, size)).beTruthy(); diff --git a/Tests/Tests/SDWebImageTestTransformer.h b/Tests/Tests/SDWebImageTestTransformer.h index 2f9040e8..c741c751 100644 --- a/Tests/Tests/SDWebImageTestTransformer.h +++ b/Tests/Tests/SDWebImageTestTransformer.h @@ -7,9 +7,9 @@ * file that was distributed with this source code. */ -#import +#import -@interface SDWebImageTestTransformer : NSObject +@interface SDWebImageTestTransformer : NSObject @property (nonatomic, strong, nullable) UIImage *testImage; From 9ee3dac978f3e5a57de5a381f368d7bf5523e28f Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 26 Apr 2018 22:13:28 +0800 Subject: [PATCH 172/361] Renaming `SDWebImageFrame` -> `SDImageFrame`. `SDWebImageCoderHelper` -> `SDImageCoderHelper` --- SDWebImage.xcodeproj/project.pbxproj | 112 +++++++++--------- SDWebImage/NSImage+Compatibility.m | 4 +- SDWebImage/SDAnimatedImage.m | 12 +- SDWebImage/SDImageCache.m | 4 +- SDWebImage/SDImageCacheDefine.m | 6 +- ...mageCoderHelper.h => SDImageCoderHelper.h} | 8 +- ...mageCoderHelper.m => SDImageCoderHelper.m} | 22 ++-- .../{SDWebImageFrame.h => SDImageFrame.h} | 4 +- .../{SDWebImageFrame.m => SDImageFrame.m} | 8 +- SDWebImage/SDWebImageAPNGCoder.m | 14 +-- SDWebImage/SDWebImageCoder.h | 4 +- SDWebImage/SDWebImageGIFCoder.m | 14 +-- SDWebImage/SDWebImageImageIOCoder.m | 8 +- SDWebImage/SDWebImageLoader.m | 8 +- SDWebImage/UIImage+ForceDecode.m | 6 +- SDWebImage/WebP/SDWebImageWebPCoder.m | 22 ++-- WebImage/SDWebImage.h | 4 +- 17 files changed, 130 insertions(+), 130 deletions(-) rename SDWebImage/{SDWebImageCoderHelper.h => SDImageCoderHelper.h} (94%) rename SDWebImage/{SDWebImageCoderHelper.m => SDImageCoderHelper.m} (96%) rename SDWebImage/{SDWebImageFrame.h => SDImageFrame.h} (82%) rename SDWebImage/{SDWebImageFrame.m => SDImageFrame.m} (78%) diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index ec3e6d5b..cf8c0109 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -458,18 +458,18 @@ 328BB6D62082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; 328BB6D72082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; 328BB6D82082581100760D6C /* SDMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB6C02082581100760D6C /* SDMemoryCache.m */; }; - 3290FA041FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3290FA051FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3290FA061FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3290FA071FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3290FA081FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3290FA091FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3290FA0A1FA478AF0047D20C /* SDWebImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */; }; - 3290FA0B1FA478AF0047D20C /* SDWebImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */; }; - 3290FA0C1FA478AF0047D20C /* SDWebImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */; }; - 3290FA0D1FA478AF0047D20C /* SDWebImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */; }; - 3290FA0E1FA478AF0047D20C /* SDWebImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */; }; - 3290FA0F1FA478AF0047D20C /* SDWebImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */; }; + 3290FA041FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3290FA051FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3290FA061FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3290FA071FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3290FA081FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3290FA091FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3290FA0A1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; + 3290FA0B1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; + 3290FA0C1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; + 3290FA0D1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; + 3290FA0E1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; + 3290FA0F1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; 329A18591FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 329A185A1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 329A185B1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -506,18 +506,18 @@ 32C0FDEA2013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; 32C0FDEB2013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; 32C0FDEC2013426C001B8F2D /* SDWebImageIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */; }; - 32CF1C071FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32CF1C081FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32CF1C091FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32CF1C0A1FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32CF1C0B1FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32CF1C0C1FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32CF1C0D1FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; - 32CF1C0E1FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; - 32CF1C0F1FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; - 32CF1C101FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; - 32CF1C111FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; - 32CF1C121FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; }; + 32CF1C071FA496B000004BD1 /* SDImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32CF1C081FA496B000004BD1 /* SDImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32CF1C091FA496B000004BD1 /* SDImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32CF1C0A1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32CF1C0B1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32CF1C0C1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32CF1C0D1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */; }; + 32CF1C0E1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */; }; + 32CF1C0F1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */; }; + 32CF1C101FA496B000004BD1 /* SDImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */; }; + 32CF1C111FA496B000004BD1 /* SDImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */; }; + 32CF1C121FA496B000004BD1 /* SDImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */; }; 32D1221E2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32D1221F2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32D122202080B2EB003685A3 /* SDImageCacheDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1614,16 +1614,16 @@ 328BB6BE2082581100760D6C /* SDDiskCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDDiskCache.m; sourceTree = ""; }; 328BB6BF2082581100760D6C /* SDMemoryCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDMemoryCache.h; sourceTree = ""; }; 328BB6C02082581100760D6C /* SDMemoryCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDMemoryCache.m; sourceTree = ""; }; - 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageFrame.h; sourceTree = ""; }; - 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageFrame.m; sourceTree = ""; }; + 3290FA021FA478AF0047D20C /* SDImageFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageFrame.h; sourceTree = ""; }; + 3290FA031FA478AF0047D20C /* SDImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageFrame.m; sourceTree = ""; }; 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImage+WebCache.h"; path = "SDWebImage/UIImage+WebCache.h"; sourceTree = ""; }; 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImage+WebCache.m"; path = "SDWebImage/UIImage+WebCache.m"; sourceTree = ""; }; 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderConfig.h; sourceTree = ""; }; 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderConfig.m; sourceTree = ""; }; 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageIndicator.h; sourceTree = ""; }; 32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageIndicator.m; sourceTree = ""; }; - 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoderHelper.h; sourceTree = ""; }; - 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCoderHelper.m; sourceTree = ""; }; + 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageCoderHelper.h; sourceTree = ""; }; + 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageCoderHelper.m; sourceTree = ""; }; 32D1221A2080B2EB003685A3 /* SDImageCacheDefine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageCacheDefine.h; sourceTree = ""; }; 32D1221B2080B2EB003685A3 /* SDImageCacheDefine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageCacheDefine.m; sourceTree = ""; }; 32D1221C2080B2EB003685A3 /* SDImageCachesManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageCachesManager.m; sourceTree = ""; }; @@ -1879,10 +1879,10 @@ 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */, 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */, 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */, - 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */, - 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */, - 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */, - 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */, + 3290FA021FA478AF0047D20C /* SDImageFrame.h */, + 3290FA031FA478AF0047D20C /* SDImageFrame.m */, + 32CF1C051FA496B000004BD1 /* SDImageCoderHelper.h */, + 32CF1C061FA496B000004BD1 /* SDImageCoderHelper.m */, ); name = Decoder; sourceTree = ""; @@ -2409,7 +2409,7 @@ 327054D7206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, 431739571CDFC8B70008FEB9 /* encode.h in Headers */, 323F8B711F38EF770092B609 /* delta_palettization_enc.h in Headers */, - 3290FA071FA478AF0047D20C /* SDWebImageFrame.h in Headers */, + 3290FA071FA478AF0047D20C /* SDImageFrame.h in Headers */, 324DF4B7200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 807A122B1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, 80377EC61F2F66D500F89830 /* webpi_dec.h in Headers */, @@ -2453,7 +2453,7 @@ 00733A641BC4880E00A5A117 /* SDWebImageOperation.h in Headers */, 32484766201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 321E60A51F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, - 32CF1C0A1FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, + 32CF1C0A1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, 80377C4D1F2F666300F89830 /* endian_inl_utils.h in Headers */, 431739581CDFC8B70008FEB9 /* format_constants.h in Headers */, 43CE75781CFE9427006C64D0 /* FLAnimatedImage.h in Headers */, @@ -2490,7 +2490,7 @@ files = ( 80377D521F2F66A700F89830 /* neon.h in Headers */, 80377D261F2F66A700F89830 /* common_sse2.h in Headers */, - 3290FA051FA478AF0047D20C /* SDWebImageFrame.h in Headers */, + 3290FA051FA478AF0047D20C /* SDImageFrame.h in Headers */, 80377C1D1F2F666300F89830 /* huffman_encode_utils.h in Headers */, 80377E9A1F2F66D400F89830 /* common_dec.h in Headers */, 32D1221F2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, @@ -2511,7 +2511,7 @@ 4314D1621D0E0E3B004B36C9 /* mux_types.h in Headers */, 4314D1631D0E0E3B004B36C9 /* demux.h in Headers */, 80377D421F2F66A700F89830 /* lossless_common.h in Headers */, - 32CF1C081FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, + 32CF1C081FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, 4314D16B1D0E0E3B004B36C9 /* encode.h in Headers */, 80377D501F2F66A700F89830 /* mips_macro.h in Headers */, 80377C291F2F666300F89830 /* thread_utils.h in Headers */, @@ -2589,7 +2589,7 @@ 80377C791F2F666400F89830 /* utils.h in Headers */, 328BB6A02081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, 323F8B721F38EF770092B609 /* delta_palettization_enc.h in Headers */, - 32CF1C0B1FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, + 32CF1C0B1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, 431BB6D91D06D2C1006A3455 /* SDWebImageManager.h in Headers */, 80377C691F2F666400F89830 /* filters_utils.h in Headers */, 80377EC81F2F66D500F89830 /* alphai_dec.h in Headers */, @@ -2617,7 +2617,7 @@ 80377E201F2F66A800F89830 /* msa_macro.h in Headers */, 80377E031F2F66A800F89830 /* dsp.h in Headers */, 80377C661F2F666400F89830 /* color_cache_utils.h in Headers */, - 3290FA081FA478AF0047D20C /* SDWebImageFrame.h in Headers */, + 3290FA081FA478AF0047D20C /* SDImageFrame.h in Headers */, 321E60A61F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, 431BB6E71D06D2C1006A3455 /* SDWebImageCompat.h in Headers */, 80377E211F2F66A800F89830 /* neon.h in Headers */, @@ -2709,7 +2709,7 @@ 4397D2C41D0DDD8C00BB2784 /* SDImageCache.h in Headers */, 3248476E201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, 4397D2C51D0DDD8C00BB2784 /* UIImageView+WebCache.h in Headers */, - 3290FA091FA478AF0047D20C /* SDWebImageFrame.h in Headers */, + 3290FA091FA478AF0047D20C /* SDImageFrame.h in Headers */, 4369C27C1D9807EC007E863A /* UIView+WebCache.h in Headers */, 80377EE21F2F66D500F89830 /* vp8i_dec.h in Headers */, 80377C8B1F2F666400F89830 /* quant_levels_utils.h in Headers */, @@ -2731,7 +2731,7 @@ 80377E761F2F66A800F89830 /* yuv.h in Headers */, 80377C7A1F2F666400F89830 /* bit_reader_inl_utils.h in Headers */, 80377E631F2F66A800F89830 /* lossless.h in Headers */, - 32CF1C0C1FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, + 32CF1C0C1FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, 43A918691D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 4397D2D81D0DDD8C00BB2784 /* UIButton+WebCache.h in Headers */, 32F7C0742030114C00873181 /* SDWebImageTransformer.h in Headers */, @@ -2807,7 +2807,7 @@ 431739511CDFC8B70008FEB9 /* format_constants.h in Headers */, 43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 323F8B701F38EF770092B609 /* delta_palettization_enc.h in Headers */, - 3290FA061FA478AF0047D20C /* SDWebImageFrame.h in Headers */, + 3290FA061FA478AF0047D20C /* SDImageFrame.h in Headers */, 324DF4B6200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 807A122A1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, 80377EB61F2F66D400F89830 /* webpi_dec.h in Headers */, @@ -2851,7 +2851,7 @@ 80377C331F2F666300F89830 /* endian_inl_utils.h in Headers */, 32484765201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 321E60A41F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, - 32CF1C091FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, + 32CF1C091FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, 4A2CAE1B1AB4BB6800B6BC39 /* SDWebImageDownloader.h in Headers */, 431739501CDFC8B70008FEB9 /* encode.h in Headers */, 323F8B881F38EF770092B609 /* histogram_enc.h in Headers */, @@ -2887,7 +2887,7 @@ 431738C21CDFC2660008FEB9 /* mux_types.h in Headers */, 431738BE1CDFC2660008FEB9 /* demux.h in Headers */, 80377BFC1F2F665300F89830 /* bit_writer_utils.h in Headers */, - 32CF1C071FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, + 32CF1C071FA496B000004BD1 /* SDImageCoderHelper.h in Headers */, 32F7C0842030719600873181 /* UIImage+Transform.h in Headers */, 431738BF1CDFC2660008FEB9 /* encode.h in Headers */, 53761316155AD0D5005750A4 /* SDImageCache.h in Headers */, @@ -2904,7 +2904,7 @@ 80377D0D1F2F66A100F89830 /* neon.h in Headers */, 431738C31CDFC2660008FEB9 /* types.h in Headers */, 80377D0C1F2F66A100F89830 /* msa_macro.h in Headers */, - 3290FA041FA478AF0047D20C /* SDWebImageFrame.h in Headers */, + 3290FA041FA478AF0047D20C /* SDImageFrame.h in Headers */, 80377D1D1F2F66A100F89830 /* yuv.h in Headers */, 43CE75D01CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */, 807A12281F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, @@ -3201,7 +3201,7 @@ 80377DD31F2F66A700F89830 /* lossless_enc.c in Sources */, 32FDE88C20888726008D7530 /* UIImage+WebP.m in Sources */, 323F8BBD1F38EF770092B609 /* predictor_enc.c in Sources */, - 3290FA0D1FA478AF0047D20C /* SDWebImageFrame.m in Sources */, + 3290FA0D1FA478AF0047D20C /* SDImageFrame.m in Sources */, 80377DBD1F2F66A700F89830 /* dec.c in Sources */, 00733A561BC4880000A5A117 /* SDWebImageDownloaderOperation.m in Sources */, 80377DE71F2F66A700F89830 /* upsampling.c in Sources */, @@ -3228,7 +3228,7 @@ 80377DC31F2F66A700F89830 /* enc_neon.c in Sources */, 80377C501F2F666300F89830 /* huffman_encode_utils.c in Sources */, 80377DE51F2F66A700F89830 /* upsampling_neon.c in Sources */, - 32CF1C101FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */, + 32CF1C101FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, 80377DAE1F2F66A700F89830 /* argb_sse2.c in Sources */, 323F8B7D1F38EF770092B609 /* frame_enc.c in Sources */, 328BB6D62082581100760D6C /* SDMemoryCache.m in Sources */, @@ -3419,7 +3419,7 @@ 80377D291F2F66A700F89830 /* cost_sse2.c in Sources */, 80377D601F2F66A700F89830 /* yuv_sse2.c in Sources */, 80377C281F2F666300F89830 /* thread_utils.c in Sources */, - 3290FA0B1FA478AF0047D20C /* SDWebImageFrame.m in Sources */, + 3290FA0B1FA478AF0047D20C /* SDImageFrame.m in Sources */, 80377C2A1F2F666300F89830 /* utils.c in Sources */, 323F8B4B1F38EF770092B609 /* backward_references_enc.c in Sources */, 807A122F1F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */, @@ -3500,7 +3500,7 @@ 4314D14B1D0E0E3B004B36C9 /* SDWebImageCompat.m in Sources */, 328BB6B12081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, 4314D14D1D0E0E3B004B36C9 /* UIImage+GIF.m in Sources */, - 32CF1C0E1FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */, + 32CF1C0E1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, 323F8B571F38EF770092B609 /* config_enc.c in Sources */, 80377D371F2F66A700F89830 /* enc_mips32.c in Sources */, 80377D431F2F66A700F89830 /* lossless_enc_mips_dsp_r2.c in Sources */, @@ -3586,7 +3586,7 @@ 80377E0F1F2F66A800F89830 /* filters_sse2.c in Sources */, 80377DED1F2F66A800F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, 80377DF81F2F66A800F89830 /* cost_sse2.c in Sources */, - 3290FA0E1FA478AF0047D20C /* SDWebImageFrame.m in Sources */, + 3290FA0E1FA478AF0047D20C /* SDImageFrame.m in Sources */, 80377E2F1F2F66A800F89830 /* yuv_sse2.c in Sources */, 431BB6AA1D06D2C1006A3455 /* SDWebImageManager.m in Sources */, 323F8B4E1F38EF770092B609 /* backward_references_enc.c in Sources */, @@ -3666,7 +3666,7 @@ 80377C701F2F666400F89830 /* quant_levels_utils.c in Sources */, 328BB6B42081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, 431BB6BD1D06D2C1006A3455 /* UIImage+GIF.m in Sources */, - 32CF1C111FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */, + 32CF1C111FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, 323F8B5A1F38EF770092B609 /* config_enc.c in Sources */, 80377E061F2F66A800F89830 /* enc_mips32.c in Sources */, 80377E121F2F66A800F89830 /* lossless_enc_mips_dsp_r2.c in Sources */, @@ -3731,9 +3731,9 @@ 320CAE202086F50500CFFC80 /* SDWebImageError.m in Sources */, 80377E6E1F2F66A800F89830 /* upsampling_msa.c in Sources */, 323F8B911F38EF770092B609 /* iterator_enc.c in Sources */, - 3290FA0F1FA478AF0047D20C /* SDWebImageFrame.m in Sources */, + 3290FA0F1FA478AF0047D20C /* SDImageFrame.m in Sources */, 80377EE01F2F66D500F89830 /* vp8_dec.c in Sources */, - 32CF1C121FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */, + 32CF1C121FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, 32B9B542206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, 80377E521F2F66A800F89830 /* filters_msa.c in Sources */, 329A18641FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, @@ -3871,7 +3871,7 @@ 80377D8E1F2F66A700F89830 /* lossless_enc.c in Sources */, 32FDE88B20888726008D7530 /* UIImage+WebP.m in Sources */, 323F8BBC1F38EF770092B609 /* predictor_enc.c in Sources */, - 3290FA0C1FA478AF0047D20C /* SDWebImageFrame.m in Sources */, + 3290FA0C1FA478AF0047D20C /* SDImageFrame.m in Sources */, 80377D781F2F66A700F89830 /* dec.c in Sources */, 80377DA21F2F66A700F89830 /* upsampling.c in Sources */, 80377C401F2F666300F89830 /* rescaler_utils.c in Sources */, @@ -3897,7 +3897,7 @@ 80377D7E1F2F66A700F89830 /* enc_neon.c in Sources */, 80377DA01F2F66A700F89830 /* upsampling_neon.c in Sources */, 80377D691F2F66A700F89830 /* argb_sse2.c in Sources */, - 32CF1C0F1FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */, + 32CF1C0F1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, 80377D6A1F2F66A700F89830 /* argb.c in Sources */, 323F8B7C1F38EF770092B609 /* frame_enc.c in Sources */, 328BB6D52082581100760D6C /* SDMemoryCache.m in Sources */, @@ -4041,7 +4041,7 @@ 80377D041F2F66A100F89830 /* lossless_enc.c in Sources */, 32FDE88920888726008D7530 /* UIImage+WebP.m in Sources */, 323F8BBA1F38EF770092B609 /* predictor_enc.c in Sources */, - 3290FA0A1FA478AF0047D20C /* SDWebImageFrame.m in Sources */, + 3290FA0A1FA478AF0047D20C /* SDImageFrame.m in Sources */, 80377CEE1F2F66A100F89830 /* dec.c in Sources */, 80377D181F2F66A100F89830 /* upsampling.c in Sources */, 80377C0C1F2F665300F89830 /* rescaler_utils.c in Sources */, @@ -4068,7 +4068,7 @@ 80377D161F2F66A100F89830 /* upsampling_neon.c in Sources */, 80377CDF1F2F66A100F89830 /* argb_sse2.c in Sources */, 80377CE01F2F66A100F89830 /* argb.c in Sources */, - 32CF1C0D1FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */, + 32CF1C0D1FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, 323F8B7A1F38EF770092B609 /* frame_enc.c in Sources */, 80377E8B1F2F66D000F89830 /* frame_dec.c in Sources */, 328BB6D32082581100760D6C /* SDMemoryCache.m in Sources */, diff --git a/SDWebImage/NSImage+Compatibility.m b/SDWebImage/NSImage+Compatibility.m index df6f7faf..9672fa11 100644 --- a/SDWebImage/NSImage+Compatibility.m +++ b/SDWebImage/NSImage+Compatibility.m @@ -10,7 +10,7 @@ #if SD_MAC -#import "SDWebImageCoderHelper.h" +#import "SDImageCoderHelper.h" @implementation NSImage (Compatibility) @@ -45,7 +45,7 @@ if (orientation != kCGImagePropertyOrientationUp) { // AppKit design is different from UIKit. Where CGImage based image rep does not respect to any orientation. Only data based image rep which contains the EXIF metadata can automatically detect orientation. // This should be nonnull, until the memory is exhausted cause `CGBitmapContextCreate` failed. - CGImageRef rotatedCGImage = [SDWebImageCoderHelper CGImageCreateDecoded:cgImage orientation:orientation]; + CGImageRef rotatedCGImage = [SDImageCoderHelper CGImageCreateDecoded:cgImage orientation:orientation]; imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; CGImageRelease(rotatedCGImage); } else { diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index 1b5da1c0..102a9752 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -11,7 +11,7 @@ #import "UIImage+WebCache.h" #import "SDWebImageCoder.h" #import "SDWebImageCodersManager.h" -#import "SDWebImageFrame.h" +#import "SDImageFrame.h" #define LOCK(...) dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER); \ __VA_ARGS__; \ @@ -199,7 +199,7 @@ static NSArray *SDBundlePreferredScales() { @property (nonatomic, strong) id coder; @property (nonatomic, assign, readwrite) SDImageFormat animatedImageFormat; -@property (atomic, copy) NSArray *loadedAnimatedImageFrames; // Mark as atomic to keep thread-safe +@property (atomic, copy) NSArray *loadedAnimatedImageFrames; // Mark as atomic to keep thread-safe @property (nonatomic, assign, getter=isAllFramesLoaded) BOOL allFramesLoaded; @end @@ -328,11 +328,11 @@ static NSArray *SDBundlePreferredScales() { #pragma mark - Preload - (void)preloadAllFrames { if (!self.isAllFramesLoaded) { - NSMutableArray *frames = [NSMutableArray arrayWithCapacity:self.animatedImageFrameCount]; + NSMutableArray *frames = [NSMutableArray arrayWithCapacity:self.animatedImageFrameCount]; for (size_t i = 0; i < self.animatedImageFrameCount; i++) { UIImage *image = [self animatedImageFrameAtIndex:i]; NSTimeInterval duration = [self animatedImageDurationAtIndex:i]; - SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:image duration:duration]; // through the image should be nonnull, used as nullable for `animatedImageFrameAtIndex:` + SDImageFrame *frame = [SDImageFrame frameWithImage:image duration:duration]; // through the image should be nonnull, used as nullable for `animatedImageFrameAtIndex:` [frames addObject:frame]; } self.loadedAnimatedImageFrames = frames; @@ -406,7 +406,7 @@ static NSArray *SDBundlePreferredScales() { return nil; } if (self.isAllFramesLoaded) { - SDWebImageFrame *frame = [self.loadedAnimatedImageFrames objectAtIndex:index]; + SDImageFrame *frame = [self.loadedAnimatedImageFrames objectAtIndex:index]; return frame.image; } return [self.coder animatedImageFrameAtIndex:index]; @@ -417,7 +417,7 @@ static NSArray *SDBundlePreferredScales() { return 0; } if (self.isAllFramesLoaded) { - SDWebImageFrame *frame = [self.loadedAnimatedImageFrames objectAtIndex:index]; + SDImageFrame *frame = [self.loadedAnimatedImageFrames objectAtIndex:index]; return frame.duration; } return [self.coder animatedImageDurationAtIndex:index]; diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 175256ff..c382fd46 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -13,7 +13,7 @@ #import "UIImage+WebCache.h" #import "SDWebImageCodersManager.h" #import "SDWebImageTransformer.h" -#import "SDWebImageCoderHelper.h" +#import "SDImageCoderHelper.h" #import "SDAnimatedImage.h" @interface SDImageCache () @@ -177,7 +177,7 @@ if (!data && image) { // If we do not have any data to detect image format, check whether it contains alpha channel to use PNG or JPEG format SDImageFormat format; - if ([SDWebImageCoderHelper CGImageContainsAlpha:image.CGImage]) { + if ([SDImageCoderHelper CGImageContainsAlpha:image.CGImage]) { format = SDImageFormatPNG; } else { format = SDImageFormatJPEG; diff --git a/SDWebImage/SDImageCacheDefine.m b/SDWebImage/SDImageCacheDefine.m index c0bfab4e..ff5e9f61 100644 --- a/SDWebImage/SDImageCacheDefine.m +++ b/SDWebImage/SDImageCacheDefine.m @@ -8,7 +8,7 @@ #import "SDImageCacheDefine.h" #import "SDWebImageCodersManager.h" -#import "SDWebImageCoderHelper.h" +#import "SDImageCoderHelper.h" #import "SDAnimatedImage.h" #import "UIImage+WebCache.h" @@ -47,9 +47,9 @@ UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSS if (shouldDecode) { BOOL shouldScaleDown = options & SDWebImageScaleDownLargeImages; if (shouldScaleDown) { - image = [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; + image = [SDImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; } else { - image = [SDWebImageCoderHelper decodedImageWithImage:image]; + image = [SDImageCoderHelper decodedImageWithImage:image]; } } } diff --git a/SDWebImage/SDWebImageCoderHelper.h b/SDWebImage/SDImageCoderHelper.h similarity index 94% rename from SDWebImage/SDWebImageCoderHelper.h rename to SDWebImage/SDImageCoderHelper.h index 30acfbf4..dcb3b491 100644 --- a/SDWebImage/SDWebImageCoderHelper.h +++ b/SDWebImage/SDImageCoderHelper.h @@ -8,9 +8,9 @@ #import #import "SDWebImageCompat.h" -#import "SDWebImageFrame.h" +#import "SDImageFrame.h" -@interface SDWebImageCoderHelper : NSObject +@interface SDImageCoderHelper : NSObject /** Return an animated image with frames array. @@ -20,7 +20,7 @@ @param frames The frames array. If no frames or frames is empty, return nil @return A animated image for rendering on UIImageView(UIKit) or NSImageView(AppKit) */ -+ (UIImage * _Nullable)animatedImageWithFrames:(NSArray * _Nullable)frames; ++ (UIImage * _Nullable)animatedImageWithFrames:(NSArray * _Nullable)frames; /** Return frames array from an animated image. @@ -30,7 +30,7 @@ @param animatedImage A animated image. If it's not animated, return nil @return The frames array */ -+ (NSArray * _Nullable)framesFromAnimatedImage:(UIImage * _Nullable)animatedImage NS_SWIFT_NAME(frames(from:)); ++ (NSArray * _Nullable)framesFromAnimatedImage:(UIImage * _Nullable)animatedImage NS_SWIFT_NAME(frames(from:)); /** Return the shared device-dependent RGB color space. This follows The Get Rule. diff --git a/SDWebImage/SDWebImageCoderHelper.m b/SDWebImage/SDImageCoderHelper.m similarity index 96% rename from SDWebImage/SDWebImageCoderHelper.m rename to SDWebImage/SDImageCoderHelper.m index 348124aa..0f2faee1 100644 --- a/SDWebImage/SDWebImageCoderHelper.m +++ b/SDWebImage/SDImageCoderHelper.m @@ -6,8 +6,8 @@ * file that was distributed with this source code. */ -#import "SDWebImageCoderHelper.h" -#import "SDWebImageFrame.h" +#import "SDImageCoderHelper.h" +#import "SDImageFrame.h" #import "NSImage+Compatibility.h" #import "NSData+ImageContentType.h" #import "SDAnimatedImageRep.h" @@ -41,9 +41,9 @@ static const CGFloat kTileTotalPixels = kSourceImageTileSizeMB * kPixelsPerMB; static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to overlap the seems where tiles meet. #endif -@implementation SDWebImageCoderHelper +@implementation SDImageCoderHelper -+ (UIImage *)animatedImageWithFrames:(NSArray *)frames { ++ (UIImage *)animatedImageWithFrames:(NSArray *)frames { NSUInteger frameCount = frames.count; if (frameCount == 0) { return nil; @@ -59,7 +59,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over NSUInteger const gcd = gcdArray(frameCount, durations); __block NSUInteger totalDuration = 0; NSMutableArray *animatedImages = [NSMutableArray arrayWithCapacity:frameCount]; - [frames enumerateObjectsUsingBlock:^(SDWebImageFrame * _Nonnull frame, NSUInteger idx, BOOL * _Nonnull stop) { + [frames enumerateObjectsUsingBlock:^(SDImageFrame * _Nonnull frame, NSUInteger idx, BOOL * _Nonnull stop) { UIImage *image = frame.image; NSUInteger duration = frame.duration * 1000; totalDuration += duration; @@ -89,7 +89,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over for (size_t i = 0; i < frameCount; i++) { @autoreleasepool { - SDWebImageFrame *frame = frames[i]; + SDImageFrame *frame = frames[i]; float frameDuration = frame.duration; CGImageRef frameImageRef = frame.image.CGImage; NSDictionary *frameProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary : @{(__bridge_transfer NSString *)kCGImagePropertyGIFDelayTime : @(frameDuration)}}; @@ -117,12 +117,12 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over return animatedImage; } -+ (NSArray *)framesFromAnimatedImage:(UIImage *)animatedImage { ++ (NSArray *)framesFromAnimatedImage:(UIImage *)animatedImage { if (!animatedImage) { return nil; } - NSMutableArray *frames = [NSMutableArray array]; + NSMutableArray *frames = [NSMutableArray array]; NSUInteger frameCount = 0; #if SD_UIKIT || SD_WATCH @@ -148,7 +148,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over if ([image isEqual:previousImage]) { repeatCount++; } else { - SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:previousImage duration:avgDuration * repeatCount]; + SDImageFrame *frame = [SDImageFrame frameWithImage:previousImage duration:avgDuration * repeatCount]; [frames addObject:frame]; repeatCount = 1; index++; @@ -156,7 +156,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over previousImage = image; // last one if (idx == frameCount - 1) { - SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:previousImage duration:avgDuration * repeatCount]; + SDImageFrame *frame = [SDImageFrame frameWithImage:previousImage duration:avgDuration * repeatCount]; [frames addObject:frame]; } }]; @@ -184,7 +184,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over [bitmapImageRep setProperty:NSImageCurrentFrame withValue:@(i)]; float frameDuration = [[bitmapImageRep valueForProperty:NSImageCurrentFrameDuration] floatValue]; NSImage *frameImage = [[NSImage alloc] initWithCGImage:bitmapImageRep.CGImage scale:scale orientation:kCGImagePropertyOrientationUp]; - SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:frameImage duration:frameDuration]; + SDImageFrame *frame = [SDImageFrame frameWithImage:frameImage duration:frameDuration]; [frames addObject:frame]; } } diff --git a/SDWebImage/SDWebImageFrame.h b/SDWebImage/SDImageFrame.h similarity index 82% rename from SDWebImage/SDWebImageFrame.h rename to SDWebImage/SDImageFrame.h index b6f87a23..ae56f9d9 100644 --- a/SDWebImage/SDWebImageFrame.h +++ b/SDWebImage/SDImageFrame.h @@ -9,9 +9,9 @@ #import #import "SDWebImageCompat.h" -@interface SDWebImageFrame : NSObject +@interface SDImageFrame : NSObject -// This class is used for creating animated images via `animatedImageWithFrames` in `SDWebImageCoderHelper`. Attention if you need to specify animated images loop count, use `sd_imageLoopCount` property in `UIImage+WebCache.h`. +// This class is used for creating animated images via `animatedImageWithFrames` in `SDImageCoderHelper`. Attention if you need to specify animated images loop count, use `sd_imageLoopCount` property in `UIImage+WebCache.h`. /** The image of current frame. You should not set an animated image. diff --git a/SDWebImage/SDWebImageFrame.m b/SDWebImage/SDImageFrame.m similarity index 78% rename from SDWebImage/SDWebImageFrame.m rename to SDWebImage/SDImageFrame.m index b0aefe54..f035af54 100644 --- a/SDWebImage/SDWebImageFrame.m +++ b/SDWebImage/SDImageFrame.m @@ -6,19 +6,19 @@ * file that was distributed with this source code. */ -#import "SDWebImageFrame.h" +#import "SDImageFrame.h" -@interface SDWebImageFrame () +@interface SDImageFrame () @property (nonatomic, strong, readwrite, nonnull) UIImage *image; @property (nonatomic, readwrite, assign) NSTimeInterval duration; @end -@implementation SDWebImageFrame +@implementation SDImageFrame + (instancetype)frameWithImage:(UIImage *)image duration:(NSTimeInterval)duration { - SDWebImageFrame *frame = [[SDWebImageFrame alloc] init]; + SDImageFrame *frame = [[SDImageFrame alloc] init]; frame.image = image; frame.duration = duration; diff --git a/SDWebImage/SDWebImageAPNGCoder.m b/SDWebImage/SDWebImageAPNGCoder.m index 61da3715..8a0ed170 100644 --- a/SDWebImage/SDWebImageAPNGCoder.m +++ b/SDWebImage/SDWebImageAPNGCoder.m @@ -11,7 +11,7 @@ #import "NSData+ImageContentType.h" #import "UIImage+WebCache.h" #import "NSImage+Compatibility.h" -#import "SDWebImageCoderHelper.h" +#import "SDImageCoderHelper.h" #import "SDAnimatedImageRep.h" // iOS 8 Image/IO framework binary does not contains these APNG contants, so we define them. Thanks Apple :) @@ -108,7 +108,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef if (decodeFirstFrame || count <= 1) { animatedImage = [[UIImage alloc] initWithData:data scale:scale]; } else { - NSMutableArray *frames = [NSMutableArray array]; + NSMutableArray *frames = [NSMutableArray array]; for (size_t i = 0; i < count; i++) { CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, i, NULL); @@ -120,13 +120,13 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; CGImageRelease(imageRef); - SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:image duration:duration]; + SDImageFrame *frame = [SDImageFrame frameWithImage:image duration:duration]; [frames addObject:frame]; } NSUInteger loopCount = [self sd_imageLoopCountWithSource:source]; - animatedImage = [SDWebImageCoderHelper animatedImageWithFrames:frames]; + animatedImage = [SDImageCoderHelper animatedImageWithFrames:frames]; animatedImage.sd_imageLoopCount = loopCount; } @@ -189,7 +189,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef NSMutableData *imageData = [NSMutableData data]; CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatPNG]; - NSArray *frames = [SDWebImageCoderHelper framesFromAnimatedImage:image]; + NSArray *frames = [SDImageCoderHelper framesFromAnimatedImage:image]; // Create an image destination. APNG does not support EXIF image orientation CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, frames.count, NULL); @@ -216,7 +216,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)properties); for (size_t i = 0; i < frames.count; i++) { - SDWebImageFrame *frame = frames[i]; + SDImageFrame *frame = frames[i]; float frameDuration = frame.duration; CGImageRef frameImageRef = frame.image.CGImage; NSDictionary *frameProperties = @{(__bridge_transfer NSString *)kCGImagePropertyPNGDictionary : @{(__bridge_transfer NSString *)kCGImagePropertyAPNGDelayTime : @(frameDuration)}}; @@ -402,7 +402,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef return nil; } // Image/IO create CGImage does not decompressed, so we do this because this is called background queue, this can avoid main queue block when rendering(especially when one more imageViews use the same image instance) - CGImageRef newImageRef = [SDWebImageCoderHelper CGImageCreateDecoded:imageRef]; + CGImageRef newImageRef = [SDImageCoderHelper CGImageCreateDecoded:imageRef]; if (!newImageRef) { newImageRef = imageRef; } else { diff --git a/SDWebImage/SDWebImageCoder.h b/SDWebImage/SDWebImageCoder.h index 6de19eca..47ffc3e6 100644 --- a/SDWebImage/SDWebImageCoder.h +++ b/SDWebImage/SDWebImageCoder.h @@ -59,7 +59,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp /** Decode the image data to image. - @note This protocol may supports decode animated image frames. You can use `+[SDWebImageCoderHelper animatedImageWithFrames:]` to produce an animated image with frames. + @note This protocol may supports decode animated image frames. You can use `+[SDImageCoderHelper animatedImageWithFrames:]` to produce an animated image with frames. @param data The image data to be decoded @param options A dictionary containing any decoding options. Pass @{SDWebImageCoderDecodeFirstFrameOnly: @(YES)} to decode the first frame only. @@ -80,7 +80,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp /** Encode the image to image data. - @note This protocol may supports encode animated image frames. You can use `+[SDWebImageCoderHelper framesFromAnimatedImage:]` to assemble an animated image with frames. + @note This protocol may supports encode animated image frames. You can use `+[SDImageCoderHelper framesFromAnimatedImage:]` to assemble an animated image with frames. @param image The image to be encoded @param format The image format to encode, you should note `SDImageFormatUndefined` format is also possible diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index 25d76028..750aa88b 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -11,7 +11,7 @@ #import "UIImage+WebCache.h" #import #import "NSData+ImageContentType.h" -#import "SDWebImageCoderHelper.h" +#import "SDImageCoderHelper.h" #import "SDAnimatedImageRep.h" @interface SDGIFCoderFrame : NSObject @@ -101,7 +101,7 @@ if (decodeFirstFrame || count <= 1) { animatedImage = [[UIImage alloc] initWithData:data scale:scale]; } else { - NSMutableArray *frames = [NSMutableArray array]; + NSMutableArray *frames = [NSMutableArray array]; for (size_t i = 0; i < count; i++) { CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, i, NULL); @@ -113,13 +113,13 @@ UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; CGImageRelease(imageRef); - SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:image duration:duration]; + SDImageFrame *frame = [SDImageFrame frameWithImage:image duration:duration]; [frames addObject:frame]; } NSUInteger loopCount = [self sd_imageLoopCountWithSource:source]; - animatedImage = [SDWebImageCoderHelper animatedImageWithFrames:frames]; + animatedImage = [SDImageCoderHelper animatedImageWithFrames:frames]; animatedImage.sd_imageLoopCount = loopCount; } @@ -271,7 +271,7 @@ NSMutableData *imageData = [NSMutableData data]; CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatGIF]; - NSArray *frames = [SDWebImageCoderHelper framesFromAnimatedImage:image]; + NSArray *frames = [SDImageCoderHelper framesFromAnimatedImage:image]; // Create an image destination. GIF does not support EXIF image orientation CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, frames.count, NULL); @@ -298,7 +298,7 @@ CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)properties); for (size_t i = 0; i < frames.count; i++) { - SDWebImageFrame *frame = frames[i]; + SDImageFrame *frame = frames[i]; float frameDuration = frame.duration; CGImageRef frameImageRef = frame.image.CGImage; NSDictionary *frameProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary : @{(__bridge_transfer NSString *)kCGImagePropertyGIFDelayTime : @(frameDuration)}}; @@ -397,7 +397,7 @@ return nil; } // Image/IO create CGImage does not decode, so we do this because this is called background queue, this can avoid main queue block when rendering(especially when one more imageViews use the same image instance) - CGImageRef newImageRef = [SDWebImageCoderHelper CGImageCreateDecoded:imageRef]; + CGImageRef newImageRef = [SDImageCoderHelper CGImageCreateDecoded:imageRef]; if (!newImageRef) { newImageRef = imageRef; } else { diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index 10c36666..274cd6d1 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -7,7 +7,7 @@ */ #import "SDWebImageImageIOCoder.h" -#import "SDWebImageCoderHelper.h" +#import "SDImageCoderHelper.h" #import "NSImage+Compatibility.h" #import #import "NSData+ImageContentType.h" @@ -159,7 +159,7 @@ } } #if SD_UIKIT || SD_WATCH - UIImageOrientation imageOrientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:_orientation]; + UIImageOrientation imageOrientation = [SDImageCoderHelper imageOrientationFromEXIFOrientation:_orientation]; image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:imageOrientation]; #else image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:_orientation]; @@ -191,7 +191,7 @@ } if (format == SDImageFormatUndefined) { - BOOL hasAlpha = [SDWebImageCoderHelper CGImageContainsAlpha:image.CGImage]; + BOOL hasAlpha = [SDImageCoderHelper CGImageContainsAlpha:image.CGImage]; if (hasAlpha) { format = SDImageFormatPNG; } else { @@ -211,7 +211,7 @@ NSMutableDictionary *properties = [NSMutableDictionary dictionary]; #if SD_UIKIT || SD_WATCH - CGImagePropertyOrientation exifOrientation = [SDWebImageCoderHelper exifOrientationFromImageOrientation:image.imageOrientation]; + CGImagePropertyOrientation exifOrientation = [SDImageCoderHelper exifOrientationFromImageOrientation:image.imageOrientation]; #else CGImagePropertyOrientation exifOrientation = kCGImagePropertyOrientationUp; #endif diff --git a/SDWebImage/SDWebImageLoader.m b/SDWebImage/SDWebImageLoader.m index f9741b36..4f7ff70e 100644 --- a/SDWebImage/SDWebImageLoader.m +++ b/SDWebImage/SDWebImageLoader.m @@ -9,7 +9,7 @@ #import "SDWebImageLoader.h" #import "SDWebImageCacheKeyFilter.h" #import "SDWebImageCodersManager.h" -#import "SDWebImageCoderHelper.h" +#import "SDImageCoderHelper.h" #import "SDAnimatedImage.h" #import "UIImage+WebCache.h" #import "objc/runtime.h" @@ -62,9 +62,9 @@ UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, if (shouldDecode) { BOOL shouldScaleDown = options & SDWebImageScaleDownLargeImages; if (shouldScaleDown) { - image = [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; + image = [SDImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; } else { - image = [SDWebImageCoderHelper decodedImageWithImage:image]; + image = [SDImageCoderHelper decodedImageWithImage:image]; } } } @@ -131,7 +131,7 @@ UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull shouldDecode = NO; } if (shouldDecode) { - image = [SDWebImageCoderHelper decodedImageWithImage:image]; + image = [SDImageCoderHelper decodedImageWithImage:image]; } // mark the image as progressive (completionBlock one are not mark as progressive) image.sd_isIncremental = YES; diff --git a/SDWebImage/UIImage+ForceDecode.m b/SDWebImage/UIImage+ForceDecode.m index dab75162..7eda3f6f 100644 --- a/SDWebImage/UIImage+ForceDecode.m +++ b/SDWebImage/UIImage+ForceDecode.m @@ -7,7 +7,7 @@ */ #import "UIImage+ForceDecode.h" -#import "SDWebImageCoderHelper.h" +#import "SDImageCoderHelper.h" #import "objc/runtime.h" @implementation UIImage (ForceDecode) @@ -25,7 +25,7 @@ if (!image) { return nil; } - return [SDWebImageCoderHelper decodedImageWithImage:image]; + return [SDImageCoderHelper decodedImageWithImage:image]; } + (UIImage *)sd_decodedAndScaledDownImageWithImage:(UIImage *)image { @@ -36,7 +36,7 @@ if (!image) { return nil; } - return [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:bytes]; + return [SDImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:bytes]; } @end diff --git a/SDWebImage/WebP/SDWebImageWebPCoder.m b/SDWebImage/WebP/SDWebImageWebPCoder.m index 9b25c5ce..616304a4 100644 --- a/SDWebImage/WebP/SDWebImageWebPCoder.m +++ b/SDWebImage/WebP/SDWebImageWebPCoder.m @@ -9,7 +9,7 @@ #ifdef SD_WEBP #import "SDWebImageWebPCoder.h" -#import "SDWebImageCoderHelper.h" +#import "SDImageCoderHelper.h" #import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" #import "UIImage+ForceDecode.h" @@ -168,13 +168,13 @@ dispatch_semaphore_signal(self->_lock); BOOL hasAlpha = flags & ALPHA_FLAG; CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; - CGContextRef canvas = CGBitmapContextCreate(NULL, canvasWidth, canvasHeight, 8, 0, [SDWebImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo); + CGContextRef canvas = CGBitmapContextCreate(NULL, canvasWidth, canvasHeight, 8, 0, [SDImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo); if (!canvas) { WebPDemuxDelete(demuxer); return nil; } - NSMutableArray *frames = [NSMutableArray array]; + NSMutableArray *frames = [NSMutableArray array]; do { @autoreleasepool { @@ -190,7 +190,7 @@ dispatch_semaphore_signal(self->_lock); CGImageRelease(imageRef); NSTimeInterval duration = [self sd_frameDurationWithIterator:iter]; - SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:image duration:duration]; + SDImageFrame *frame = [SDImageFrame frameWithImage:image duration:duration]; [frames addObject:frame]; } @@ -200,7 +200,7 @@ dispatch_semaphore_signal(self->_lock); WebPDemuxDelete(demuxer); CGContextRelease(canvas); - UIImage *animatedImage = [SDWebImageCoderHelper animatedImageWithFrames:frames]; + UIImage *animatedImage = [SDImageCoderHelper animatedImageWithFrames:frames]; animatedImage.sd_imageLoopCount = loopCount; return animatedImage; @@ -251,7 +251,7 @@ dispatch_semaphore_signal(self->_lock); size_t rgbaSize = last_y * stride; CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, rgba, rgbaSize, NULL); - CGColorSpaceRef colorSpaceRef = [SDWebImageCoderHelper colorSpaceGetDeviceRGB]; + CGColorSpaceRef colorSpaceRef = [SDImageCoderHelper colorSpaceGetDeviceRGB]; CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst; size_t components = 4; @@ -270,7 +270,7 @@ dispatch_semaphore_signal(self->_lock); return nil; } - CGContextRef canvas = CGBitmapContextCreate(NULL, width, height, 8, 0, [SDWebImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo); + CGContextRef canvas = CGBitmapContextCreate(NULL, width, height, 8, 0, [SDImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo); if (!canvas) { CGImageRelease(imageRef); return nil; @@ -393,7 +393,7 @@ dispatch_semaphore_signal(self->_lock); size_t bitsPerComponent = 8; size_t bitsPerPixel = 32; size_t bytesPerRow = config.output.u.RGBA.stride; - CGColorSpaceRef colorSpaceRef = [SDWebImageCoderHelper colorSpaceGetDeviceRGB]; + CGColorSpaceRef colorSpaceRef = [SDImageCoderHelper colorSpaceGetDeviceRGB]; CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); @@ -428,7 +428,7 @@ dispatch_semaphore_signal(self->_lock); if ([options valueForKey:SDWebImageCoderEncodeCompressionQuality]) { compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue]; } - NSArray *frames = [SDWebImageCoderHelper framesFromAnimatedImage:image]; + NSArray *frames = [SDImageCoderHelper framesFromAnimatedImage:image]; BOOL encodeFirstFrame = [options[SDWebImageCoderEncodeFirstFrameOnly] boolValue]; if (encodeFirstFrame || frames.count == 0) { @@ -441,7 +441,7 @@ dispatch_semaphore_signal(self->_lock); return nil; } for (size_t i = 0; i < frames.count; i++) { - SDWebImageFrame *currentFrame = frames[i]; + SDImageFrame *currentFrame = frames[i]; NSData *webpData = [self sd_encodedWebpDataWithImage:currentFrame.image quality:compressionQuality]; int duration = currentFrame.duration * 1000; WebPMuxFrameInfo frame = { .bitstream.bytes = webpData.bytes, @@ -662,7 +662,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { if (!_canvas) { CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; bitmapInfo |= _hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; - CGContextRef canvas = CGBitmapContextCreate(NULL, _canvasWidth, _canvasHeight, 8, 0, [SDWebImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo); + CGContextRef canvas = CGBitmapContextCreate(NULL, _canvasWidth, _canvasHeight, 8, 0, [SDImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo); if (!canvas) { return nil; } diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index ed37b422..a94c8515 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -57,8 +57,8 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import -#import -#import +#import +#import #import #import #import From 15bceab71c1c995ee07c1279fc92200d11243a69 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 26 Apr 2018 22:39:52 +0800 Subject: [PATCH 173/361] Rename `SDWebImageCoder` to `SDImageCoder`. Rename `SDWebImageProgressiveCoder` to `SDProgressiveImageCoder` Rename `SDWebImageAnimatedCoder` to `SDAnimatedImageCoder` --- SDWebImage.xcodeproj/project.pbxproj | 56 +++++++++---------- SDWebImage/SDAnimatedImage.h | 8 +-- SDWebImage/SDAnimatedImage.m | 22 ++++---- SDWebImage/SDAnimatedImageView.h | 2 +- SDWebImage/SDImageCacheDefine.m | 2 +- .../{SDWebImageCoder.h => SDImageCoder.h} | 52 ++++++++--------- SDWebImage/SDImageCoder.m | 15 +++++ SDWebImage/SDWebImageAPNGCoder.h | 4 +- SDWebImage/SDWebImageAPNGCoder.m | 34 +++++------ SDWebImage/SDWebImageCoder.m | 15 ----- SDWebImage/SDWebImageCodersManager.h | 12 ++-- SDWebImage/SDWebImageCodersManager.m | 36 ++++++------ SDWebImage/SDWebImageGIFCoder.h | 4 +- SDWebImage/SDWebImageGIFCoder.m | 34 +++++------ SDWebImage/SDWebImageImageIOCoder.h | 4 +- SDWebImage/SDWebImageImageIOCoder.m | 24 ++++---- SDWebImage/SDWebImageLoader.h | 2 +- SDWebImage/SDWebImageLoader.m | 18 +++--- SDWebImage/UIImage+GIF.m | 2 +- SDWebImage/UIImage+MultiFormat.m | 4 +- SDWebImage/WebP/SDWebImageWebPCoder.h | 4 +- SDWebImage/WebP/SDWebImageWebPCoder.m | 34 +++++------ SDWebImage/WebP/UIImage+WebP.m | 2 +- WebImage/SDWebImage.h | 2 +- 24 files changed, 196 insertions(+), 196 deletions(-) rename SDWebImage/{SDWebImageCoder.h => SDImageCoder.h} (75%) create mode 100644 SDWebImage/SDImageCoder.m delete mode 100644 SDWebImage/SDWebImageCoder.m diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index ec3e6d5b..0607de48 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -75,18 +75,18 @@ 321B37982083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */; }; 321DB3612011D4D70015D2CB /* NSButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321DB3622011D4D70015D2CB /* NSButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */; }; - 321E60861F38E8C800405457 /* SDWebImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDWebImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60871F38E8C800405457 /* SDWebImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDWebImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60881F38E8C800405457 /* SDWebImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDWebImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60891F38E8C800405457 /* SDWebImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDWebImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E608A1F38E8C800405457 /* SDWebImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDWebImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E608B1F38E8C800405457 /* SDWebImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDWebImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E608C1F38E8C800405457 /* SDWebImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDWebImageCoder.m */; }; - 321E608D1F38E8C800405457 /* SDWebImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDWebImageCoder.m */; }; - 321E608E1F38E8C800405457 /* SDWebImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDWebImageCoder.m */; }; - 321E608F1F38E8C800405457 /* SDWebImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDWebImageCoder.m */; }; - 321E60901F38E8C800405457 /* SDWebImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDWebImageCoder.m */; }; - 321E60911F38E8C800405457 /* SDWebImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDWebImageCoder.m */; }; + 321E60861F38E8C800405457 /* SDImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E60871F38E8C800405457 /* SDImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E60881F38E8C800405457 /* SDImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E60891F38E8C800405457 /* SDImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E608A1F38E8C800405457 /* SDImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E608B1F38E8C800405457 /* SDImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E608C1F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; + 321E608D1F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; + 321E608E1F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; + 321E608F1F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; + 321E60901F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; + 321E60911F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; 321E60941F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDWebImageImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321E60951F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDWebImageImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321E60961F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDWebImageImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1551,8 +1551,8 @@ 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageLoadersManager.m; sourceTree = ""; }; 321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSButton+WebCache.h"; path = "SDWebImage/NSButton+WebCache.h"; sourceTree = ""; }; 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSButton+WebCache.m"; path = "SDWebImage/NSButton+WebCache.m"; sourceTree = ""; }; - 321E60841F38E8C800405457 /* SDWebImageCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoder.h; sourceTree = ""; }; - 321E60851F38E8C800405457 /* SDWebImageCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCoder.m; sourceTree = ""; }; + 321E60841F38E8C800405457 /* SDImageCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageCoder.h; sourceTree = ""; }; + 321E60851F38E8C800405457 /* SDImageCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageCoder.m; sourceTree = ""; }; 321E60921F38E8ED00405457 /* SDWebImageImageIOCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageImageIOCoder.h; sourceTree = ""; }; 321E60931F38E8ED00405457 /* SDWebImageImageIOCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageImageIOCoder.m; sourceTree = ""; }; 321E60A01F38E8F600405457 /* SDWebImageGIFCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageGIFCoder.h; sourceTree = ""; }; @@ -1871,8 +1871,8 @@ children = ( 807A12261F89636300EC2A9B /* SDWebImageCodersManager.h */, 807A12271F89636300EC2A9B /* SDWebImageCodersManager.m */, - 321E60841F38E8C800405457 /* SDWebImageCoder.h */, - 321E60851F38E8C800405457 /* SDWebImageCoder.m */, + 321E60841F38E8C800405457 /* SDImageCoder.h */, + 321E60851F38E8C800405457 /* SDImageCoder.m */, 321E60921F38E8ED00405457 /* SDWebImageImageIOCoder.h */, 321E60931F38E8ED00405457 /* SDWebImageImageIOCoder.m */, 321E60A01F38E8F600405457 /* SDWebImageGIFCoder.h */, @@ -2439,7 +2439,7 @@ 00733A661BC4880E00A5A117 /* SDWebImageDownloaderOperation.h in Headers */, 80377C5D1F2F666300F89830 /* thread_utils.h in Headers */, 328BB6D02082581100760D6C /* SDMemoryCache.h in Headers */, - 321E60891F38E8C800405457 /* SDWebImageCoder.h in Headers */, + 321E60891F38E8C800405457 /* SDImageCoder.h in Headers */, 00733A721BC4880E00A5A117 /* UIView+WebCacheOperation.h in Headers */, 321B37842083290E00C0EA77 /* SDWebImageLoader.h in Headers */, 80377C481F2F666300F89830 /* bit_reader_utils.h in Headers */, @@ -2521,7 +2521,7 @@ 80377C121F2F666300F89830 /* bit_reader_inl_utils.h in Headers */, 4314D1701D0E0E3B004B36C9 /* mux.h in Headers */, 321B378E2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, - 321E60871F38E8C800405457 /* SDWebImageCoder.h in Headers */, + 321E60871F38E8C800405457 /* SDImageCoder.h in Headers */, 80377EA21F2F66D400F89830 /* vp8i_dec.h in Headers */, 320CAE162086F50500CFFC80 /* SDWebImageError.h in Headers */, 3248476A201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, @@ -2594,7 +2594,7 @@ 80377C691F2F666400F89830 /* filters_utils.h in Headers */, 80377EC81F2F66D500F89830 /* alphai_dec.h in Headers */, 43A62A1B1D0E0A800089D7DD /* decode.h in Headers */, - 321E608A1F38E8C800405457 /* SDWebImageCoder.h in Headers */, + 321E608A1F38E8C800405457 /* SDImageCoder.h in Headers */, 32484767201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80377C601F2F666400F89830 /* bit_reader_inl_utils.h in Headers */, 32FDE89920888726008D7530 /* UIImage+WebP.h in Headers */, @@ -2760,7 +2760,7 @@ 4397D2E61D0DDD8C00BB2784 /* encode.h in Headers */, 32FDE89A20888726008D7530 /* UIImage+WebP.h in Headers */, 80377C7C1F2F666400F89830 /* bit_reader_utils.h in Headers */, - 321E608B1F38E8C800405457 /* SDWebImageCoder.h in Headers */, + 321E608B1F38E8C800405457 /* SDImageCoder.h in Headers */, 323F8B731F38EF770092B609 /* delta_palettization_enc.h in Headers */, 321E60C31F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 32D122352080B2EB003685A3 /* SDImageCachesManager.h in Headers */, @@ -2837,7 +2837,7 @@ 4A2CAE251AB4BB7000B6BC39 /* SDWebImagePrefetcher.h in Headers */, 80377C431F2F666300F89830 /* thread_utils.h in Headers */, 328BB6CF2082581100760D6C /* SDMemoryCache.h in Headers */, - 321E60881F38E8C800405457 /* SDWebImageCoder.h in Headers */, + 321E60881F38E8C800405457 /* SDImageCoder.h in Headers */, 4A2CAE371AB4BB7500B6BC39 /* UIView+WebCacheOperation.h in Headers */, 321B37832083290E00C0EA77 /* SDWebImageLoader.h in Headers */, 80377C2E1F2F666300F89830 /* bit_reader_utils.h in Headers */, @@ -2960,7 +2960,7 @@ 323F8B861F38EF770092B609 /* histogram_enc.h in Headers */, 321B37812083290E00C0EA77 /* SDWebImageLoader.h in Headers */, 323F8BF61F38EF770092B609 /* animi.h in Headers */, - 321E60861F38E8C800405457 /* SDWebImageCoder.h in Headers */, + 321E60861F38E8C800405457 /* SDImageCoder.h in Headers */, 80377C0D1F2F665300F89830 /* rescaler_utils.h in Headers */, 32484763201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80377E911F2F66D000F89830 /* vp8_dec.h in Headers */, @@ -3302,7 +3302,7 @@ 323F8BD51F38EF770092B609 /* tree_enc.c in Sources */, 80377DBB1F2F66A700F89830 /* dec_sse2.c in Sources */, 323F8B831F38EF770092B609 /* histogram_enc.c in Sources */, - 321E608F1F38E8C800405457 /* SDWebImageCoder.m in Sources */, + 321E608F1F38E8C800405457 /* SDImageCoder.m in Sources */, 00733A581BC4880000A5A117 /* SDWebImageManager.m in Sources */, 323F8B411F38EF770092B609 /* alpha_enc.c in Sources */, 323F8BC31F38EF770092B609 /* quant_enc.c in Sources */, @@ -3399,7 +3399,7 @@ 80377D4B1F2F66A700F89830 /* lossless_msa.c in Sources */, 323F8B5D1F38EF770092B609 /* cost_enc.c in Sources */, 80377D3B1F2F66A700F89830 /* enc_sse41.c in Sources */, - 321E608D1F38E8C800405457 /* SDWebImageCoder.m in Sources */, + 321E608D1F38E8C800405457 /* SDImageCoder.m in Sources */, 80377D3A1F2F66A700F89830 /* enc_sse2.c in Sources */, 80377D381F2F66A700F89830 /* enc_msa.c in Sources */, 4314D1311D0E0E3B004B36C9 /* SDWebImageDownloader.m in Sources */, @@ -3566,7 +3566,7 @@ 80377E1A1F2F66A800F89830 /* lossless_msa.c in Sources */, 323F8B601F38EF770092B609 /* cost_enc.c in Sources */, 80377E0A1F2F66A800F89830 /* enc_sse41.c in Sources */, - 321E60901F38E8C800405457 /* SDWebImageCoder.m in Sources */, + 321E60901F38E8C800405457 /* SDImageCoder.m in Sources */, 80377E091F2F66A800F89830 /* enc_sse2.c in Sources */, 431BB6921D06D2C1006A3455 /* NSData+ImageContentType.m in Sources */, 80377E071F2F66A800F89830 /* enc_msa.c in Sources */, @@ -3706,7 +3706,7 @@ 80377E471F2F66A800F89830 /* dec.c in Sources */, 80377C921F2F666400F89830 /* utils.c in Sources */, 4397D27E1D0DDD8C00BB2784 /* UIImage+GIF.m in Sources */, - 321E60911F38E8C800405457 /* SDWebImageCoder.m in Sources */, + 321E60911F38E8C800405457 /* SDImageCoder.m in Sources */, 80377C8A1F2F666400F89830 /* quant_levels_utils.c in Sources */, 4397D2F71D0DE2DF00BB2784 /* NSImage+Compatibility.m in Sources */, 80377E751F2F66A800F89830 /* yuv.c in Sources */, @@ -3970,7 +3970,7 @@ 323F8BD41F38EF770092B609 /* tree_enc.c in Sources */, 80377D651F2F66A700F89830 /* alpha_processing_sse2.c in Sources */, 323F8B821F38EF770092B609 /* histogram_enc.c in Sources */, - 321E608E1F38E8C800405457 /* SDWebImageCoder.m in Sources */, + 321E608E1F38E8C800405457 /* SDImageCoder.m in Sources */, 4A2CAE301AB4BB7500B6BC39 /* UIImage+MultiFormat.m in Sources */, 323F8B401F38EF770092B609 /* alpha_enc.c in Sources */, 80377C2D1F2F666300F89830 /* bit_reader_utils.c in Sources */, @@ -4140,7 +4140,7 @@ 323F8BD21F38EF770092B609 /* tree_enc.c in Sources */, 80377CDB1F2F66A100F89830 /* alpha_processing_sse2.c in Sources */, 323F8B801F38EF770092B609 /* histogram_enc.c in Sources */, - 321E608C1F38E8C800405457 /* SDWebImageCoder.m in Sources */, + 321E608C1F38E8C800405457 /* SDImageCoder.m in Sources */, 5376130E155AD0D5005750A4 /* UIButton+WebCache.m in Sources */, 323F8B3E1F38EF770092B609 /* alpha_enc.c in Sources */, 80377BF91F2F665300F89830 /* bit_reader_utils.c in Sources */, diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h index 92282f56..2c829f29 100644 --- a/SDWebImage/SDAnimatedImage.h +++ b/SDWebImage/SDAnimatedImage.h @@ -7,7 +7,7 @@ */ #import "SDWebImageCompat.h" -#import "SDWebImageCoder.h" +#import "SDImageCoder.h" /** @@ -18,13 +18,13 @@ @required /** 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. However, for progressive image decoding, we will use this with animated coder which conforms to `SDWebImageProgressiveCoder` as well instead. + @note Normally we use `initWithData:scale:` to create custom animated image class. However, for progressive image decoding, we will use this with animated coder which conforms to `SDProgressiveImageCoder` as well instead. @param animatedCoder An animated coder which conform `SDWebImageAnimatedCoder` protocol @param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property. @return An initialized object */ -- (nullable instancetype)initWithAnimatedCoder:(nonnull id)animatedCoder scale:(CGFloat)scale; +- (nullable instancetype)initWithAnimatedCoder:(nonnull id)animatedCoder scale:(CGFloat)scale; @optional /** @@ -63,7 +63,7 @@ - (nullable instancetype)initWithContentsOfFile:(nonnull NSString *)path; - (nullable instancetype)initWithData:(nonnull NSData *)data; - (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale; -- (nullable instancetype)initWithAnimatedCoder:(nonnull id)animatedCoder scale:(CGFloat)scale; +- (nullable instancetype)initWithAnimatedCoder:(nonnull id)animatedCoder scale:(CGFloat)scale; /** Current animated image format. diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index 1b5da1c0..b9bb6a5f 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -9,7 +9,7 @@ #import "SDAnimatedImage.h" #import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" -#import "SDWebImageCoder.h" +#import "SDImageCoder.h" #import "SDWebImageCodersManager.h" #import "SDWebImageFrame.h" @@ -197,7 +197,7 @@ static NSArray *SDBundlePreferredScales() { @interface SDAnimatedImage () -@property (nonatomic, strong) id coder; +@property (nonatomic, strong) id coder; @property (nonatomic, assign, readwrite) SDImageFormat animatedImageFormat; @property (atomic, copy) NSArray *loadedAnimatedImageFrames; // Mark as atomic to keep thread-safe @property (nonatomic, assign, getter=isAllFramesLoaded) BOOL allFramesLoaded; @@ -285,11 +285,11 @@ static NSArray *SDBundlePreferredScales() { return nil; } data = [data copy]; // avoid mutable data - id animatedCoder = nil; - for (idcoder in [SDWebImageCodersManager sharedManager].coders) { - if ([coder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { + id animatedCoder = nil; + for (idcoder in [SDWebImageCodersManager sharedManager].coders) { + if ([coder conformsToProtocol:@protocol(SDAnimatedImageCoder)]) { if ([coder canDecodeFromData:data]) { - animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data options:@{SDWebImageCoderDecodeScaleFactor : @(scale)}]; + animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data options:@{SDImageCoderDecodeScaleFactor : @(scale)}]; break; } } @@ -300,7 +300,7 @@ static NSArray *SDBundlePreferredScales() { return [self initWithAnimatedCoder:animatedCoder scale:scale]; } -- (instancetype)initWithAnimatedCoder:(id)animatedCoder scale:(CGFloat)scale { +- (instancetype)initWithAnimatedCoder:(id)animatedCoder scale:(CGFloat)scale { if (!animatedCoder) { return nil; } @@ -356,11 +356,11 @@ static NSArray *SDBundlePreferredScales() { if (!animatedImageData) { return self; } - id animatedCoder = nil; - for (idcoder in [SDWebImageCodersManager sharedManager].coders) { - if ([coder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { + id animatedCoder = nil; + for (idcoder in [SDWebImageCodersManager sharedManager].coders) { + if ([coder conformsToProtocol:@protocol(SDAnimatedImageCoder)]) { if ([coder canDecodeFromData:animatedImageData]) { - animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:animatedImageData options:@{SDWebImageCoderDecodeScaleFactor : @(scale)}]; + animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:animatedImageData options:@{SDImageCoderDecodeScaleFactor : @(scale)}]; break; } } diff --git a/SDWebImage/SDAnimatedImageView.h b/SDWebImage/SDAnimatedImageView.h index 5038b1cb..34806cf2 100644 --- a/SDWebImage/SDAnimatedImageView.h +++ b/SDWebImage/SDAnimatedImageView.h @@ -53,7 +53,7 @@ /** Whehter or not to enable incremental image load for animated image. This is for the animated image which `sd_isIncremental` is YES (See `UIImage+WebCache.h`). If enable, animated image rendering will stop at the last frame available currently, and continue when another `setImage:` trigger, where the new animated image's `animatedImageData` should be updated from the previous one. If the `sd_isIncremental` is NO. The incremental image load stop. @note If you are confused about this description, open Chrome browser to view some large GIF images with low network speed to see the animation behavior. - @note The best practice to use incremental load is using `initWithAnimatedCoder:scale` in `SDAnimatedImage` with animated coder which conform to `SDWebImageProgressiveCoder` as well. Then call incremental update and incremental decode method to produce the image. + @note The best practice to use incremental load is using `initWithAnimatedCoder:scale` in `SDAnimatedImage` with animated coder which conform to `SDProgressiveImageCoder` as well. Then call incremental update and incremental decode method to produce the image. Default is YES. Set to NO to only render the static poster for incremental animated image. */ @property (nonatomic, assign) BOOL shouldIncrementalLoad; diff --git a/SDWebImage/SDImageCacheDefine.m b/SDWebImage/SDImageCacheDefine.m index c0bfab4e..e3414c7a 100644 --- a/SDWebImage/SDImageCacheDefine.m +++ b/SDWebImage/SDImageCacheDefine.m @@ -33,7 +33,7 @@ UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSS } } if (!image) { - image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; + image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}]; } if (image) { BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; diff --git a/SDWebImage/SDWebImageCoder.h b/SDWebImage/SDImageCoder.h similarity index 75% rename from SDWebImage/SDWebImageCoder.h rename to SDWebImage/SDImageCoder.h index 6de19eca..efa2352e 100644 --- a/SDWebImage/SDWebImageCoder.h +++ b/SDWebImage/SDImageCoder.h @@ -10,33 +10,33 @@ #import "SDWebImageCompat.h" #import "NSData+ImageContentType.h" -typedef NSString * SDWebImageCoderOption NS_STRING_ENUM; -typedef NSDictionary SDWebImageCoderOptions; +typedef NSString * SDImageCoderOption NS_STRING_ENUM; +typedef NSDictionary SDImageCoderOptions; #pragma mark - Coder Options // These options are for image decoding /** A Boolean value indicating whether to decode the first frame only for animated image during decoding. (NSNumber). If not provide, decode animated image if need. - @note works for `SDWebImageCoder`. + @note works for `SDImageCoder`. */ -FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderDecodeFirstFrameOnly; +FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderDecodeFirstFrameOnly; /** A CGFloat value which is greater than or equal to 1.0. This value specify the image scale factor for decoding. If not provide, use 1.0. (NSNumber) - @note works for `SDWebImageCoder`, `SDWebImageProgressiveCoder`, `SDWebImageAnimatedCoder`. + @note works for `SDImageCoder`, `SDProgressiveImageCoder`, `SDWebImageAnimatedCoder`. */ -FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderDecodeScaleFactor; +FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderDecodeScaleFactor; // These options are for image encoding /** A Boolean value indicating whether to encode the first frame only for animated image during encoding. (NSNumber). If not provide, encode animated image if need. - @note works for `SDWebImageCoder`. + @note works for `SDImageCoder`. */ -FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeFirstFrameOnly; +FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeFirstFrameOnly; /** A double value between 0.0-1.0 indicating the encode compression quality to produce the image data. 1.0 resulting in no compression and 0.0 resulting in the maximum compression possible. If not provide, use 1.0. (NSNumber) - @note works for `SDWebImageCoder` + @note works for `SDImageCoder` */ -FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeCompressionQuality; +FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeCompressionQuality; #pragma mark - Coder /** @@ -45,7 +45,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp You do not need to specify image scale during decoding because we may scale image later. @note Pay attention that these methods are not called from main queue. */ -@protocol SDWebImageCoder +@protocol SDImageCoder @required #pragma mark - Decoding @@ -59,14 +59,14 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp /** Decode the image data to image. - @note This protocol may supports decode animated image frames. You can use `+[SDWebImageCoderHelper animatedImageWithFrames:]` to produce an animated image with frames. + @note This protocol may supports decode animated image frames. You can use `+[SDImageCoderHelper animatedImageWithFrames:]` to produce an animated image with frames. @param data The image data to be decoded - @param options A dictionary containing any decoding options. Pass @{SDWebImageCoderDecodeFirstFrameOnly: @(YES)} to decode the first frame only. + @param options A dictionary containing any decoding options. Pass @{SDImageCoderDecodeFirstFrameOnly: @(YES)} to decode the first frame only. @return The decoded image from data */ - (nullable UIImage *)decodedImageWithData:(nullable NSData *)data - options:(nullable SDWebImageCoderOptions *)options; + options:(nullable SDImageCoderOptions *)options; #pragma mark - Encoding @@ -80,16 +80,16 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp /** Encode the image to image data. - @note This protocol may supports encode animated image frames. You can use `+[SDWebImageCoderHelper framesFromAnimatedImage:]` to assemble an animated image with frames. + @note This protocol may supports encode animated image frames. You can use `+[SDImageCoderHelper framesFromAnimatedImage:]` to assemble an animated image with frames. @param image The image to be encoded @param format The image format to encode, you should note `SDImageFormatUndefined` format is also possible - @param options A dictionary containing any encoding options. Pass @{SDWebImageCoderEncodeCompressionQuality: @(1)} to specify compression quality. + @param options A dictionary containing any encoding options. Pass @{SDImageCoderEncodeCompressionQuality: @(1)} to specify compression quality. @return The encoded image data */ - (nullable NSData *)encodedDataWithImage:(nullable UIImage *)image format:(SDImageFormat)format - options:(nullable SDWebImageCoderOptions *)options; + options:(nullable SDImageCoderOptions *)options; @end @@ -99,7 +99,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp These methods are all required to implement. @note Pay attention that these methods are not called from main queue. */ -@protocol SDWebImageProgressiveCoder +@protocol SDProgressiveImageCoder @required /** @@ -114,10 +114,10 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp Because incremental decoding need to keep the decoded context, we will alloc a new instance with the same class for each download operation to avoid conflicts This init method should not return nil - @param options A dictionary containing any progressive decoding options (instance-level). Pass @{SDWebImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for progressive animated image (each frames should use the same scale). + @param options A dictionary containing any progressive decoding options (instance-level). Pass @{SDImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for progressive animated image (each frames should use the same scale). @return A new instance to do incremental decoding for the specify image format */ -- (nonnull instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options; +- (nonnull instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)options; /** Update the incremental decoding when new image data available @@ -131,10 +131,10 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp Incremental decode the current image data to image. @note Due to the performance issue for progressive decoding and the integration for image view. This method may only return the first frame image even if the image data is animated image. If you want progressive animated image decoding, conform to `SDWebImageAnimatedCoder` protocol as well and use `animatedImageFrameAtIndex:` instead. - @param options A dictionary containing any progressive decoding options. Pass @{SDWebImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for progressive image + @param options A dictionary containing any progressive decoding options. Pass @{SDImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for progressive image @return The decoded image from current data */ -- (nullable UIImage *)incrementalDecodedImageWithOptions:(nullable SDWebImageCoderOptions *)options; +- (nullable UIImage *)incrementalDecodedImageWithOptions:(nullable SDImageCoderOptions *)options; @end @@ -187,9 +187,9 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp #pragma mark - Animated Coder /** - This is the animated image coder protocol for custom animated image class like `SDAnimatedImage`. Through it inherit from `SDWebImageCoder`. We currentlly only use the method `canDecodeFromData:` to detect the proper coder for specify animated image format. + This is the animated image coder protocol for custom animated image class like `SDAnimatedImage`. Through it inherit from `SDImageCoder`. We currentlly only use the method `canDecodeFromData:` to detect the proper coder for specify animated image format. */ -@protocol SDWebImageAnimatedCoder +@protocol SDAnimatedImageCoder @required /** @@ -198,9 +198,9 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp After the instance created, we may call methods in `SDAnimatedImageProvider` to produce animated image frame. @param data The animated image data to be decode - @param options A dictionary containing any animated decoding options (instance-level). Pass @{SDWebImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for animated image (each frames should use the same scale). + @param options A dictionary containing any animated decoding options (instance-level). Pass @{SDImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for animated image (each frames should use the same scale). @return A new instance to do animated decoding for specify image data */ -- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data options:(nullable SDWebImageCoderOptions *)options; +- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data options:(nullable SDImageCoderOptions *)options; @end diff --git a/SDWebImage/SDImageCoder.m b/SDWebImage/SDImageCoder.m new file mode 100644 index 00000000..e2ac717b --- /dev/null +++ b/SDWebImage/SDImageCoder.m @@ -0,0 +1,15 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDImageCoder.h" + +SDImageCoderOption const SDImageCoderDecodeFirstFrameOnly = @"decodeFirstFrameOnly"; +SDImageCoderOption const SDImageCoderDecodeScaleFactor = @"decodeScaleFactor"; + +SDImageCoderOption const SDImageCoderEncodeFirstFrameOnly = @"encodeFirstFrameOnly"; +SDImageCoderOption const SDImageCoderEncodeCompressionQuality = @"encodeCompressionQuality"; diff --git a/SDWebImage/SDWebImageAPNGCoder.h b/SDWebImage/SDWebImageAPNGCoder.h index 8abf9fd7..489513c0 100644 --- a/SDWebImage/SDWebImageAPNGCoder.h +++ b/SDWebImage/SDWebImageAPNGCoder.h @@ -7,12 +7,12 @@ */ #import -#import "SDWebImageCoder.h" +#import "SDImageCoder.h" /** Built in coder using ImageIO that supports APNG encoding/decoding */ -@interface SDWebImageAPNGCoder : NSObject +@interface SDWebImageAPNGCoder : NSObject @property (nonatomic, class, readonly, nonnull) SDWebImageAPNGCoder *sharedCoder; diff --git a/SDWebImage/SDWebImageAPNGCoder.m b/SDWebImage/SDWebImageAPNGCoder.m index 61da3715..5a2ac166 100644 --- a/SDWebImage/SDWebImageAPNGCoder.m +++ b/SDWebImage/SDWebImageAPNGCoder.m @@ -76,13 +76,13 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef return ([NSData sd_imageFormatForImageData:data] == SDImageFormatPNG); } -- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { +- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderOptions *)options { if (!data) { return nil; } CGFloat scale = 1; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } @@ -104,7 +104,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef size_t count = CGImageSourceGetCount(source); UIImage *animatedImage; - BOOL decodeFirstFrame = [options[SDWebImageCoderDecodeFirstFrameOnly] boolValue]; + BOOL decodeFirstFrame = [options[SDImageCoderDecodeFirstFrameOnly] boolValue]; if (decodeFirstFrame || count <= 1) { animatedImage = [[UIImage alloc] initWithData:data scale:scale]; } else { @@ -178,7 +178,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef return (format == SDImageFormatPNG); } -- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDWebImageCoderOptions *)options { +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDImageCoderOptions *)options { if (!image) { return nil; } @@ -199,12 +199,12 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef } NSMutableDictionary *properties = [NSMutableDictionary dictionary]; double compressionQuality = 1; - if ([options valueForKey:SDWebImageCoderEncodeCompressionQuality]) { - compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue]; + if ([options valueForKey:SDImageCoderEncodeCompressionQuality]) { + compressionQuality = [[options valueForKey:SDImageCoderEncodeCompressionQuality] doubleValue]; } [properties setValue:@(compressionQuality) forKey:(__bridge_transfer NSString *)kCGImageDestinationLossyCompressionQuality]; - BOOL encodeFirstFrame = [options[SDWebImageCoderEncodeFirstFrameOnly] boolValue]; + BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; if (encodeFirstFrame || frames.count == 0) { // for static single PNG images CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); @@ -240,14 +240,14 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef return ([NSData sd_imageFormatForImageData:data] == SDImageFormatPNG); } -- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options { +- (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)options { self = [super init]; if (self) { CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatPNG]; _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceTypeIdentifierHint : (__bridge_transfer NSString *)imageUTType}); CGFloat scale = 1; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } @@ -288,7 +288,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef [self scanAndCheckFramesValidWithImageSource:_imageSource]; } -- (UIImage *)incrementalDecodedImageWithOptions:(SDWebImageCoderOptions *)options { +- (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options { UIImage *image; if (_width + _height > 0) { @@ -297,8 +297,8 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef if (partialImageRef) { CGFloat scale = _scale; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } @@ -316,7 +316,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef } #pragma mark - SDWebImageAnimatedCoder -- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data options:(nullable SDWebImageCoderOptions *)options { +- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data options:(nullable SDImageCoderOptions *)options { if (!data) { return nil; } @@ -333,8 +333,8 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef return nil; } CGFloat scale = 1; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } diff --git a/SDWebImage/SDWebImageCoder.m b/SDWebImage/SDWebImageCoder.m deleted file mode 100644 index 2778ea3c..00000000 --- a/SDWebImage/SDWebImageCoder.m +++ /dev/null @@ -1,15 +0,0 @@ -/* - * This file is part of the SDWebImage package. - * (c) Olivier Poitrey - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#import "SDWebImageCoder.h" - -SDWebImageCoderOption const SDWebImageCoderDecodeFirstFrameOnly = @"decodeFirstFrameOnly"; -SDWebImageCoderOption const SDWebImageCoderDecodeScaleFactor = @"decodeScaleFactor"; - -SDWebImageCoderOption const SDWebImageCoderEncodeFirstFrameOnly = @"encodeFirstFrameOnly"; -SDWebImageCoderOption const SDWebImageCoderEncodeCompressionQuality = @"encodeCompressionQuality"; diff --git a/SDWebImage/SDWebImageCodersManager.h b/SDWebImage/SDWebImageCodersManager.h index fc40e5f8..ef68bd75 100644 --- a/SDWebImage/SDWebImageCodersManager.h +++ b/SDWebImage/SDWebImageCodersManager.h @@ -7,7 +7,7 @@ */ #import -#import "SDWebImageCoder.h" +#import "SDImageCoder.h" /** Global object holding the array of coders, so that we avoid passing them from object to object. @@ -24,12 +24,12 @@ Coders ------ - A coder must conform to the `SDWebImageCoder` protocol or even to `SDWebImageProgressiveCoder` if it supports progressive decoding + A coder must conform to the `SDImageCoder` protocol or even to `SDProgressiveImageCoder` if it supports progressive decoding Conformance is important because that way, they will implement `canDecodeFromData` or `canEncodeToFormat` Those methods are called on each coder in the array (using the priority order) until one of them returns YES. That means that coder can decode that data / encode to that format */ -@interface SDWebImageCodersManager : NSObject +@interface SDWebImageCodersManager : NSObject /** Returns the global shared coders manager instance. @@ -39,20 +39,20 @@ /** All coders in coders manager. The coders array is a priority queue, which means the later added coder will have the highest priority */ -@property (nonatomic, copy, readwrite, nullable) NSArray> *coders; +@property (nonatomic, copy, readwrite, nullable) NSArray> *coders; /** Add a new coder to the end of coders array. Which has the highest priority. @param coder coder */ -- (void)addCoder:(nonnull id)coder; +- (void)addCoder:(nonnull id)coder; /** Remove a coder in the coders array. @param coder coder */ -- (void)removeCoder:(nonnull id)coder; +- (void)removeCoder:(nonnull id)coder; @end diff --git a/SDWebImage/SDWebImageCodersManager.m b/SDWebImage/SDWebImageCodersManager.m index 47c4f9a6..add2bbae 100644 --- a/SDWebImage/SDWebImageCodersManager.m +++ b/SDWebImage/SDWebImageCodersManager.m @@ -40,7 +40,7 @@ - (instancetype)init { if (self = [super init]) { // initialize with default coders - NSMutableArray> *mutableCoders = [@[[SDWebImageImageIOCoder sharedCoder], [SDWebImageGIFCoder sharedCoder], [SDWebImageAPNGCoder sharedCoder]] mutableCopy]; + NSMutableArray> *mutableCoders = [@[[SDWebImageImageIOCoder sharedCoder], [SDWebImageGIFCoder sharedCoder], [SDWebImageAPNGCoder sharedCoder]] mutableCopy]; #ifdef SD_WEBP [mutableCoders addObject:[SDWebImageWebPCoder sharedCoder]]; #endif @@ -52,12 +52,12 @@ #pragma mark - Coder IO operations -- (void)addCoder:(nonnull id)coder { - if (![coder conformsToProtocol:@protocol(SDWebImageCoder)]) { +- (void)addCoder:(nonnull id)coder { + if (![coder conformsToProtocol:@protocol(SDImageCoder)]) { return; } LOCK(self.codersLock); - NSMutableArray> *mutableCoders = [self.coders mutableCopy]; + NSMutableArray> *mutableCoders = [self.coders mutableCopy]; if (!mutableCoders) { mutableCoders = [NSMutableArray array]; } @@ -66,23 +66,23 @@ UNLOCK(self.codersLock); } -- (void)removeCoder:(nonnull id)coder { - if (![coder conformsToProtocol:@protocol(SDWebImageCoder)]) { +- (void)removeCoder:(nonnull id)coder { + if (![coder conformsToProtocol:@protocol(SDImageCoder)]) { return; } LOCK(self.codersLock); - NSMutableArray> *mutableCoders = [self.coders mutableCopy]; + NSMutableArray> *mutableCoders = [self.coders mutableCopy]; [mutableCoders removeObject:coder]; self.coders = [mutableCoders copy]; UNLOCK(self.codersLock); } -#pragma mark - SDWebImageCoder +#pragma mark - SDImageCoder - (BOOL)canDecodeFromData:(NSData *)data { LOCK(self.codersLock); - NSArray> *coders = self.coders; + NSArray> *coders = self.coders; UNLOCK(self.codersLock); - for (id coder in coders.reverseObjectEnumerator) { + for (id coder in coders.reverseObjectEnumerator) { if ([coder canDecodeFromData:data]) { return YES; } @@ -92,9 +92,9 @@ - (BOOL)canEncodeToFormat:(SDImageFormat)format { LOCK(self.codersLock); - NSArray> *coders = self.coders; + NSArray> *coders = self.coders; UNLOCK(self.codersLock); - for (id coder in coders.reverseObjectEnumerator) { + for (id coder in coders.reverseObjectEnumerator) { if ([coder canEncodeToFormat:format]) { return YES; } @@ -102,15 +102,15 @@ return NO; } -- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { +- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderOptions *)options { if (!data) { return nil; } UIImage *image; LOCK(self.codersLock); - NSArray> *coders = self.coders; + NSArray> *coders = self.coders; UNLOCK(self.codersLock); - for (id coder in coders.reverseObjectEnumerator) { + for (id coder in coders.reverseObjectEnumerator) { if ([coder canDecodeFromData:data]) { image = [coder decodedImageWithData:data options:options]; break; @@ -120,14 +120,14 @@ return image; } -- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDWebImageCoderOptions *)options { +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDImageCoderOptions *)options { if (!image) { return nil; } LOCK(self.codersLock); - NSArray> *coders = self.coders; + NSArray> *coders = self.coders; UNLOCK(self.codersLock); - for (id coder in coders.reverseObjectEnumerator) { + for (id coder in coders.reverseObjectEnumerator) { if ([coder canEncodeToFormat:format]) { return [coder encodedDataWithImage:image format:format options:nil]; } diff --git a/SDWebImage/SDWebImageGIFCoder.h b/SDWebImage/SDWebImageGIFCoder.h index c92cbcea..6b9c7ec2 100644 --- a/SDWebImage/SDWebImageGIFCoder.h +++ b/SDWebImage/SDWebImageGIFCoder.h @@ -7,7 +7,7 @@ */ #import -#import "SDWebImageCoder.h" +#import "SDImageCoder.h" /** Built in coder using ImageIO that supports GIF encoding/decoding @@ -15,7 +15,7 @@ @note Use `SDWebImageGIFCoder` for fully animated GIFs. For `UIImageView`, it will produce animated `UIImage`(`NSImage` on macOS) for rendering. For `SDAnimatedImageView`, it will use `SDAnimatedImage` for rendering. @note The recommended approach for animated GIFs is using `SDAnimatedImage` with `SDAnimatedImageView`. It's more performant than `UIImageView` for GIF displaying(especially on memory usage) */ -@interface SDWebImageGIFCoder : NSObject +@interface SDWebImageGIFCoder : NSObject @property (nonatomic, class, readonly, nonnull) SDWebImageGIFCoder *sharedCoder; diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDWebImageGIFCoder.m index 25d76028..efffaffd 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDWebImageGIFCoder.m @@ -69,13 +69,13 @@ return ([NSData sd_imageFormatForImageData:data] == SDImageFormatGIF); } -- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { +- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderOptions *)options { if (!data) { return nil; } CGFloat scale = 1; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } @@ -97,7 +97,7 @@ size_t count = CGImageSourceGetCount(source); UIImage *animatedImage; - BOOL decodeFirstFrame = [options[SDWebImageCoderDecodeFirstFrameOnly] boolValue]; + BOOL decodeFirstFrame = [options[SDImageCoderDecodeFirstFrameOnly] boolValue]; if (decodeFirstFrame || count <= 1) { animatedImage = [[UIImage alloc] initWithData:data scale:scale]; } else { @@ -180,14 +180,14 @@ return ([NSData sd_imageFormatForImageData:data] == SDImageFormatGIF); } -- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options { +- (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)options { self = [super init]; if (self) { CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatGIF]; _imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceTypeIdentifierHint : (__bridge_transfer NSString *)imageUTType}); CGFloat scale = 1; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } @@ -228,7 +228,7 @@ [self scanAndCheckFramesValidWithImageSource:_imageSource]; } -- (UIImage *)incrementalDecodedImageWithOptions:(SDWebImageCoderOptions *)options { +- (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options { UIImage *image; if (_width + _height > 0) { @@ -237,8 +237,8 @@ if (partialImageRef) { CGFloat scale = _scale; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } @@ -260,7 +260,7 @@ return (format == SDImageFormatGIF); } -- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDWebImageCoderOptions *)options { +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDImageCoderOptions *)options { if (!image) { return nil; } @@ -281,12 +281,12 @@ } NSMutableDictionary *properties = [NSMutableDictionary dictionary]; double compressionQuality = 1; - if ([options valueForKey:SDWebImageCoderEncodeCompressionQuality]) { - compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue]; + if ([options valueForKey:SDImageCoderEncodeCompressionQuality]) { + compressionQuality = [[options valueForKey:SDImageCoderEncodeCompressionQuality] doubleValue]; } [properties setValue:@(compressionQuality) forKey:(__bridge_transfer NSString *)kCGImageDestinationLossyCompressionQuality]; - BOOL encodeFirstFrame = [options[SDWebImageCoderEncodeFirstFrameOnly] boolValue]; + BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; if (encodeFirstFrame || frames.count == 0) { // for static single GIF images CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); @@ -317,7 +317,7 @@ } #pragma mark - SDWebImageAnimatedCoder -- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data options:(nullable SDWebImageCoderOptions *)options { +- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data options:(nullable SDImageCoderOptions *)options { if (!data) { return nil; } @@ -334,8 +334,8 @@ return nil; } CGFloat scale = 1; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } diff --git a/SDWebImage/SDWebImageImageIOCoder.h b/SDWebImage/SDWebImageImageIOCoder.h index b43c9c0d..9551a696 100644 --- a/SDWebImage/SDWebImageImageIOCoder.h +++ b/SDWebImage/SDWebImageImageIOCoder.h @@ -7,7 +7,7 @@ */ #import -#import "SDWebImageCoder.h" +#import "SDImageCoder.h" /** Built in coder that supports PNG, JPEG, TIFF, includes support for progressive decoding. @@ -23,7 +23,7 @@ Encode(Software): macOS 10.13 Encode(Hardware): !Simulator && ((iOS 11 && A10FusionChip) || (macOS 10.13 && 6thGenerationIntelCPU)) */ -@interface SDWebImageImageIOCoder : NSObject +@interface SDWebImageImageIOCoder : NSObject @property (nonatomic, class, readonly, nonnull) SDWebImageImageIOCoder *sharedCoder; diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDWebImageImageIOCoder.m index 10c36666..071d6801 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDWebImageImageIOCoder.m @@ -60,13 +60,13 @@ } } -- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { +- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderOptions *)options { if (!data) { return nil; } CGFloat scale = 1; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } @@ -91,13 +91,13 @@ } } -- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options { +- (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)options { self = [super init]; if (self) { _imageSource = CGImageSourceCreateIncremental(NULL); CGFloat scale = 1; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } @@ -143,7 +143,7 @@ } } -- (UIImage *)incrementalDecodedImageWithOptions:(SDWebImageCoderOptions *)options { +- (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options { UIImage *image; if (_width + _height > 0) { @@ -152,8 +152,8 @@ if (partialImageRef) { CGFloat scale = _scale; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } @@ -185,7 +185,7 @@ } } -- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDWebImageCoderOptions *)options { +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDImageCoderOptions *)options { if (!image) { return nil; } @@ -217,8 +217,8 @@ #endif [properties setValue:@(exifOrientation) forKey:(__bridge_transfer NSString *)kCGImagePropertyOrientation]; double compressionQuality = 1; - if ([options valueForKey:SDWebImageCoderEncodeCompressionQuality]) { - compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue]; + if ([options valueForKey:SDImageCoderEncodeCompressionQuality]) { + compressionQuality = [[options valueForKey:SDImageCoderEncodeCompressionQuality] doubleValue]; } [properties setValue:@(compressionQuality) forKey:(__bridge_transfer NSString *)kCGImageDestinationLossyCompressionQuality]; diff --git a/SDWebImage/SDWebImageLoader.h b/SDWebImage/SDWebImageLoader.h index 7ec47ac5..13e6ec5f 100644 --- a/SDWebImage/SDWebImageLoader.h +++ b/SDWebImage/SDWebImageLoader.h @@ -10,7 +10,7 @@ #import "SDWebImageDefine.h" #import "SDWebImageOperation.h" -@protocol SDWebImageProgressiveCoder; +@protocol SDProgressiveImageCoder; typedef void(^SDWebImageLoaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL); typedef void(^SDWebImageLoaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished); diff --git a/SDWebImage/SDWebImageLoader.m b/SDWebImage/SDWebImageLoader.m index f9741b36..dd55b65e 100644 --- a/SDWebImage/SDWebImageLoader.m +++ b/SDWebImage/SDWebImageLoader.m @@ -47,7 +47,7 @@ UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, } } if (!image) { - image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; + image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}]; } if (image) { BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; @@ -91,13 +91,13 @@ UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull if (scale < 1) { scale = 1; } - id progressiveCoder = objc_getAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey); + id progressiveCoder = objc_getAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey); if (!progressiveCoder) { // We need to create a new instance for progressive decoding to avoid conflicts - for (idcoder in [SDWebImageCodersManager sharedManager].coders.reverseObjectEnumerator) { - if ([coder conformsToProtocol:@protocol(SDWebImageProgressiveCoder)] && - [((id)coder) canIncrementalDecodeFromData:imageData]) { - progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:@{SDWebImageCoderDecodeScaleFactor : @(scale)}]; + for (idcoder in [SDWebImageCodersManager sharedManager].coders.reverseObjectEnumerator) { + if ([coder conformsToProtocol:@protocol(SDProgressiveImageCoder)] && + [((id)coder) canIncrementalDecodeFromData:imageData]) { + progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:@{SDImageCoderDecodeScaleFactor : @(scale)}]; break; } } @@ -113,13 +113,13 @@ UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull // check whether we should use `SDAnimatedImage` if ([context valueForKey:SDWebImageContextAnimatedImageClass]) { Class animatedImageClass = [context valueForKey:SDWebImageContextAnimatedImageClass]; - if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)] && [progressiveCoder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) { - image = [[animatedImageClass alloc] initWithAnimatedCoder:(id)progressiveCoder scale:scale]; + if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)] && [progressiveCoder conformsToProtocol:@protocol(SDAnimatedImageCoder)]) { + image = [[animatedImageClass alloc] initWithAnimatedCoder:(id)progressiveCoder scale:scale]; } } } if (!image) { - image = [progressiveCoder incrementalDecodedImageWithOptions:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; + image = [progressiveCoder incrementalDecodedImageWithOptions:@{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}]; } if (image) { BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; diff --git a/SDWebImage/UIImage+GIF.m b/SDWebImage/UIImage+GIF.m index 0698a923..512baa21 100644 --- a/SDWebImage/UIImage+GIF.m +++ b/SDWebImage/UIImage+GIF.m @@ -20,7 +20,7 @@ if (!data) { return nil; } - SDWebImageCoderOptions *options = @{SDWebImageCoderDecodeFirstFrameOnly : @(firstFrameOnly)}; + SDImageCoderOptions *options = @{SDImageCoderDecodeFirstFrameOnly : @(firstFrameOnly)}; return [[SDWebImageGIFCoder sharedCoder] decodedImageWithData:data options:options]; } diff --git a/SDWebImage/UIImage+MultiFormat.m b/SDWebImage/UIImage+MultiFormat.m index b0145bc8..2fc7e9f7 100644 --- a/SDWebImage/UIImage+MultiFormat.m +++ b/SDWebImage/UIImage+MultiFormat.m @@ -22,7 +22,7 @@ if (scale < 1) { scale = 1; } - SDWebImageCoderOptions *options = @{SDWebImageCoderDecodeScaleFactor : @(scale)}; + SDImageCoderOptions *options = @{SDImageCoderDecodeScaleFactor : @(scale)}; return [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:options]; } @@ -35,7 +35,7 @@ } - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat compressionQuality:(double)compressionQuality { - SDWebImageCoderOptions *options = @{SDWebImageCoderEncodeCompressionQuality : @(compressionQuality)}; + SDImageCoderOptions *options = @{SDImageCoderEncodeCompressionQuality : @(compressionQuality)}; return [[SDWebImageCodersManager sharedManager] encodedDataWithImage:self format:imageFormat options:options]; } diff --git a/SDWebImage/WebP/SDWebImageWebPCoder.h b/SDWebImage/WebP/SDWebImageWebPCoder.h index 052c6fc0..461a6840 100644 --- a/SDWebImage/WebP/SDWebImageWebPCoder.h +++ b/SDWebImage/WebP/SDWebImageWebPCoder.h @@ -9,12 +9,12 @@ #ifdef SD_WEBP #import -#import "SDWebImageCoder.h" +#import "SDImageCoder.h" /** Built in coder that supports WebP and animated WebP */ -@interface SDWebImageWebPCoder : NSObject +@interface SDWebImageWebPCoder : NSObject @property (nonatomic, class, readonly, nonnull) SDWebImageWebPCoder *sharedCoder; diff --git a/SDWebImage/WebP/SDWebImageWebPCoder.m b/SDWebImage/WebP/SDWebImageWebPCoder.m index 9b25c5ce..6a998b02 100644 --- a/SDWebImage/WebP/SDWebImageWebPCoder.m +++ b/SDWebImage/WebP/SDWebImageWebPCoder.m @@ -99,7 +99,7 @@ dispatch_semaphore_signal(self->_lock); return ([NSData sd_imageFormatForImageData:data] == SDImageFormatWebP); } -- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { +- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderOptions *)options { if (!data) { return nil; } @@ -115,10 +115,10 @@ dispatch_semaphore_signal(self->_lock); uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS); BOOL hasAnimation = flags & ANIMATION_FLAG; - BOOL decodeFirstFrame = [[options valueForKey:SDWebImageCoderDecodeFirstFrameOnly] boolValue]; + BOOL decodeFirstFrame = [[options valueForKey:SDImageCoderDecodeFirstFrameOnly] boolValue]; CGFloat scale = 1; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } @@ -207,14 +207,14 @@ dispatch_semaphore_signal(self->_lock); } #pragma mark - Progressive Decode -- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options { +- (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)options { self = [super init]; if (self) { // Progressive images need transparent, so always use premultiplied RGBA _idec = WebPINewRGB(MODE_bgrA, NULL, 0, 0); CGFloat scale = 1; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } @@ -237,7 +237,7 @@ dispatch_semaphore_signal(self->_lock); // libwebp current does not support progressive decoding for animated image, so no need to scan and update the frame information } -- (UIImage *)incrementalDecodedImageWithOptions:(SDWebImageCoderOptions *)options { +- (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options { UIImage *image; int width = 0; @@ -285,8 +285,8 @@ dispatch_semaphore_signal(self->_lock); return nil; } CGFloat scale = _scale; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } @@ -417,7 +417,7 @@ dispatch_semaphore_signal(self->_lock); return (format == SDImageFormatWebP); } -- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDWebImageCoderOptions *)options { +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDImageCoderOptions *)options { if (!image) { return nil; } @@ -425,12 +425,12 @@ dispatch_semaphore_signal(self->_lock); NSData *data; double compressionQuality = 1; - if ([options valueForKey:SDWebImageCoderEncodeCompressionQuality]) { - compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue]; + if ([options valueForKey:SDImageCoderEncodeCompressionQuality]) { + compressionQuality = [[options valueForKey:SDImageCoderEncodeCompressionQuality] doubleValue]; } NSArray *frames = [SDWebImageCoderHelper framesFromAnimatedImage:image]; - BOOL encodeFirstFrame = [options[SDWebImageCoderEncodeFirstFrameOnly] boolValue]; + BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; if (encodeFirstFrame || frames.count == 0) { // for static single webp image data = [self sd_encodedWebpDataWithImage:image quality:compressionQuality]; @@ -526,7 +526,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { } #pragma mark - SDWebImageAnimatedCoder -- (instancetype)initWithAnimatedImageData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { +- (instancetype)initWithAnimatedImageData:(NSData *)data options:(nullable SDImageCoderOptions *)options { if (!data) { return nil; } @@ -545,8 +545,8 @@ static void FreeImageData(void *info, const void *data, size_t size) { return nil; } CGFloat scale = 1; - if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) { - scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue]; + if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { + scale = [[options valueForKey:SDImageCoderDecodeScaleFactor] doubleValue]; if (scale < 1) { scale = 1; } diff --git a/SDWebImage/WebP/UIImage+WebP.m b/SDWebImage/WebP/UIImage+WebP.m index db1fa6a9..919af914 100644 --- a/SDWebImage/WebP/UIImage+WebP.m +++ b/SDWebImage/WebP/UIImage+WebP.m @@ -21,7 +21,7 @@ if (!data) { return nil; } - SDWebImageCoderOptions *options = @{SDWebImageCoderDecodeFirstFrameOnly : @(firstFrameOnly)}; + SDImageCoderOptions *options = @{SDImageCoderDecodeFirstFrameOnly : @(firstFrameOnly)}; return [[SDWebImageWebPCoder sharedCoder] decodedImageWithData:data options:options]; } diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index ed37b422..c383d2c8 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -53,7 +53,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import -#import +#import #import #import #import From 6e5a0ea5f0e1d83214be9f83c46ed16defa5d7f4 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 26 Apr 2018 22:51:50 +0800 Subject: [PATCH 174/361] Rename Image/IO GIF APNG WebP coders to without `Web` prefix. Rename `SDWebImageCodersManager` to `SDImageCodersManager` --- SDWebImage.xcodeproj/project.pbxproj | 280 +++++++++--------- SDWebImage/SDAnimatedImage.h | 4 +- SDWebImage/SDAnimatedImage.m | 6 +- SDWebImage/SDAnimatedImageRep.h | 4 +- SDWebImage/SDAnimatedImageRep.m | 14 +- ...WebImageAPNGCoder.h => SDImageAPNGCoder.h} | 4 +- ...WebImageAPNGCoder.m => SDImageAPNGCoder.m} | 10 +- SDWebImage/SDImageCache.m | 4 +- SDWebImage/SDImageCacheDefine.m | 4 +- SDWebImage/SDImageCoder.h | 6 +- ...CodersManager.h => SDImageCodersManager.h} | 4 +- ...CodersManager.m => SDImageCodersManager.m} | 18 +- ...SDWebImageGIFCoder.h => SDImageGIFCoder.h} | 6 +- ...SDWebImageGIFCoder.m => SDImageGIFCoder.m} | 10 +- ...ebImageImageIOCoder.h => SDImageIOCoder.h} | 6 +- ...ebImageImageIOCoder.m => SDImageIOCoder.m} | 8 +- SDWebImage/SDWebImageLoader.m | 6 +- SDWebImage/UIImage+GIF.m | 4 +- SDWebImage/UIImage+MultiFormat.m | 6 +- ...WebImageWebPCoder.h => SDImageWebPCoder.h} | 4 +- ...WebImageWebPCoder.m => SDImageWebPCoder.m} | 10 +- SDWebImage/WebP/UIImage+WebP.m | 4 +- WebImage/SDWebImage.h | 10 +- 23 files changed, 216 insertions(+), 216 deletions(-) rename SDWebImage/{SDWebImageAPNGCoder.h => SDImageAPNGCoder.h} (68%) rename SDWebImage/{SDWebImageAPNGCoder.m => SDImageAPNGCoder.m} (98%) rename SDWebImage/{SDWebImageCodersManager.h => SDImageCodersManager.h} (93%) rename SDWebImage/{SDWebImageCodersManager.m => SDImageCodersManager.m} (89%) rename SDWebImage/{SDWebImageGIFCoder.h => SDImageGIFCoder.h} (62%) rename SDWebImage/{SDWebImageGIFCoder.m => SDImageGIFCoder.m} (98%) rename SDWebImage/{SDWebImageImageIOCoder.h => SDImageIOCoder.h} (85%) rename SDWebImage/{SDWebImageImageIOCoder.m => SDImageIOCoder.m} (98%) rename SDWebImage/WebP/{SDWebImageWebPCoder.h => SDImageWebPCoder.h} (68%) rename SDWebImage/WebP/{SDWebImageWebPCoder.m => SDImageWebPCoder.m} (99%) diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 0607de48..cf04e41b 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -87,30 +87,30 @@ 321E608F1F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; 321E60901F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; 321E60911F38E8C800405457 /* SDImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60851F38E8C800405457 /* SDImageCoder.m */; }; - 321E60941F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDWebImageImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60951F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDWebImageImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60961F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDWebImageImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60971F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDWebImageImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60981F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDWebImageImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60991F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDWebImageImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E609A1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDWebImageImageIOCoder.m */; }; - 321E609B1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDWebImageImageIOCoder.m */; }; - 321E609C1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDWebImageImageIOCoder.m */; }; - 321E609D1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDWebImageImageIOCoder.m */; }; - 321E609E1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDWebImageImageIOCoder.m */; }; - 321E609F1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDWebImageImageIOCoder.m */; }; - 321E60A21F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDWebImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60A31F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDWebImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60A41F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDWebImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60A51F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDWebImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60A61F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDWebImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60A71F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDWebImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321E60A81F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */; }; - 321E60A91F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */; }; - 321E60AA1F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */; }; - 321E60AB1F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */; }; - 321E60AC1F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */; }; - 321E60AD1F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */; }; + 321E60941F38E8ED00405457 /* SDImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E60951F38E8ED00405457 /* SDImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E60961F38E8ED00405457 /* SDImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E60971F38E8ED00405457 /* SDImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E60981F38E8ED00405457 /* SDImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E60991F38E8ED00405457 /* SDImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60921F38E8ED00405457 /* SDImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E609A1F38E8ED00405457 /* SDImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDImageIOCoder.m */; }; + 321E609B1F38E8ED00405457 /* SDImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDImageIOCoder.m */; }; + 321E609C1F38E8ED00405457 /* SDImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDImageIOCoder.m */; }; + 321E609D1F38E8ED00405457 /* SDImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDImageIOCoder.m */; }; + 321E609E1F38E8ED00405457 /* SDImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDImageIOCoder.m */; }; + 321E609F1F38E8ED00405457 /* SDImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60931F38E8ED00405457 /* SDImageIOCoder.m */; }; + 321E60A21F38E8F600405457 /* SDImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E60A31F38E8F600405457 /* SDImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E60A41F38E8F600405457 /* SDImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E60A51F38E8F600405457 /* SDImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E60A61F38E8F600405457 /* SDImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E60A71F38E8F600405457 /* SDImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60A01F38E8F600405457 /* SDImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321E60A81F38E8F600405457 /* SDImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */; }; + 321E60A91F38E8F600405457 /* SDImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */; }; + 321E60AA1F38E8F600405457 /* SDImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */; }; + 321E60AB1F38E8F600405457 /* SDImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */; }; + 321E60AC1F38E8F600405457 /* SDImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */; }; + 321E60AD1F38E8F600405457 /* SDImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */; }; 321E60BE1F38E91700405457 /* UIImage+ForceDecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321E60BF1F38E91700405457 /* UIImage+ForceDecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321E60C01F38E91700405457 /* UIImage+ForceDecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -398,18 +398,18 @@ 325312D1200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; }; 325312D2200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; }; 325312D3200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; }; - 327054D4206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 327054D5206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 327054D6206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 327054D7206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 327054D8206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 327054D9206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 327054DA206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; - 327054DB206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; - 327054DC206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; - 327054DD206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; - 327054DE206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; - 327054DF206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */; }; + 327054D4206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 327054D5206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 327054D6206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 327054D7206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 327054D8206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 327054D9206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 327054DA206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; }; + 327054DB206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; }; + 327054DC206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; }; + 327054DD206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; }; + 327054DE206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; }; + 327054DF206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; }; 328BB69C2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 328BB69D2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 328BB69E2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -597,24 +597,24 @@ 32FDE88C20888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; 32FDE88D20888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; 32FDE88E20888726008D7530 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88520888726008D7530 /* UIImage+WebP.m */; }; - 32FDE88F20888726008D7530 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89020888726008D7530 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89120888726008D7530 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89220888726008D7530 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89320888726008D7530 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89420888726008D7530 /* SDWebImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE88F20888726008D7530 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89020888726008D7530 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89120888726008D7530 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89220888726008D7530 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89320888726008D7530 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32FDE89420888726008D7530 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88620888726008D7530 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32FDE89520888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32FDE89620888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32FDE89720888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32FDE89820888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32FDE89920888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32FDE89A20888726008D7530 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 32FDE88720888726008D7530 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32FDE89B20888726008D7530 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */; }; - 32FDE89C20888726008D7530 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */; }; - 32FDE89D20888726008D7530 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */; }; - 32FDE89E20888726008D7530 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */; }; - 32FDE89F20888726008D7530 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */; }; - 32FDE8A020888726008D7530 /* SDWebImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */; }; + 32FDE89B20888726008D7530 /* SDImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDImageWebPCoder.m */; }; + 32FDE89C20888726008D7530 /* SDImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDImageWebPCoder.m */; }; + 32FDE89D20888726008D7530 /* SDImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDImageWebPCoder.m */; }; + 32FDE89E20888726008D7530 /* SDImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDImageWebPCoder.m */; }; + 32FDE89F20888726008D7530 /* SDImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDImageWebPCoder.m */; }; + 32FDE8A020888726008D7530 /* SDImageWebPCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FDE88820888726008D7530 /* SDImageWebPCoder.m */; }; 32FDE8A220888789008D7530 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32FDE8A320888789008D7530 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4314D1231D0E0E3B004B36C9 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D86148C56230056699D /* SDImageCache.m */; }; @@ -1519,18 +1519,18 @@ 80377EE41F2F66D500F89830 /* vp8li_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E841F2F66D000F89830 /* vp8li_dec.h */; }; 80377EE51F2F66D500F89830 /* webp_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 80377E851F2F66D000F89830 /* webp_dec.c */; }; 80377EE61F2F66D500F89830 /* webpi_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 80377E861F2F66D000F89830 /* webpi_dec.h */; }; - 807A12281F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDWebImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 807A12291F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDWebImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 807A122A1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDWebImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 807A122B1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDWebImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 807A122C1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDWebImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 807A122D1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDWebImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 807A122E1F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDWebImageCodersManager.m */; }; - 807A122F1F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDWebImageCodersManager.m */; }; - 807A12301F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDWebImageCodersManager.m */; }; - 807A12311F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDWebImageCodersManager.m */; }; - 807A12321F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDWebImageCodersManager.m */; }; - 807A12331F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDWebImageCodersManager.m */; }; + 807A12281F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 807A12291F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 807A122A1F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 807A122B1F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 807A122C1F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 807A122D1F89636300EC2A9B /* SDImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 807A12261F89636300EC2A9B /* SDImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 807A122E1F89636300EC2A9B /* SDImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDImageCodersManager.m */; }; + 807A122F1F89636300EC2A9B /* SDImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDImageCodersManager.m */; }; + 807A12301F89636300EC2A9B /* SDImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDImageCodersManager.m */; }; + 807A12311F89636300EC2A9B /* SDImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDImageCodersManager.m */; }; + 807A12321F89636300EC2A9B /* SDImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDImageCodersManager.m */; }; + 807A12331F89636300EC2A9B /* SDImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 807A12271F89636300EC2A9B /* SDImageCodersManager.m */; }; A18A6CC7172DC28500419892 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; A18A6CC9172DC28500419892 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = A18A6CC6172DC28500419892 /* UIImage+GIF.m */; }; AB615303192DA24600A2D8E9 /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1553,10 +1553,10 @@ 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSButton+WebCache.m"; path = "SDWebImage/NSButton+WebCache.m"; sourceTree = ""; }; 321E60841F38E8C800405457 /* SDImageCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageCoder.h; sourceTree = ""; }; 321E60851F38E8C800405457 /* SDImageCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageCoder.m; sourceTree = ""; }; - 321E60921F38E8ED00405457 /* SDWebImageImageIOCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageImageIOCoder.h; sourceTree = ""; }; - 321E60931F38E8ED00405457 /* SDWebImageImageIOCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageImageIOCoder.m; sourceTree = ""; }; - 321E60A01F38E8F600405457 /* SDWebImageGIFCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageGIFCoder.h; sourceTree = ""; }; - 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageGIFCoder.m; sourceTree = ""; }; + 321E60921F38E8ED00405457 /* SDImageIOCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageIOCoder.h; sourceTree = ""; }; + 321E60931F38E8ED00405457 /* SDImageIOCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageIOCoder.m; sourceTree = ""; }; + 321E60A01F38E8F600405457 /* SDImageGIFCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageGIFCoder.h; sourceTree = ""; }; + 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageGIFCoder.m; sourceTree = ""; }; 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+ForceDecode.h"; sourceTree = ""; }; 321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+ForceDecode.m"; sourceTree = ""; }; 323F8B131F38EF770092B609 /* alpha_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alpha_enc.c; sourceTree = ""; }; @@ -1604,8 +1604,8 @@ 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDefine.m; sourceTree = ""; }; 325312C6200F09910046BF1E /* SDWebImageTransition.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTransition.h; sourceTree = ""; }; 325312C7200F09910046BF1E /* SDWebImageTransition.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransition.m; sourceTree = ""; }; - 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageAPNGCoder.h; sourceTree = ""; }; - 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageAPNGCoder.m; sourceTree = ""; }; + 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageAPNGCoder.h; sourceTree = ""; }; + 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageAPNGCoder.m; sourceTree = ""; }; 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCacheKeyFilter.h; sourceTree = ""; }; 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCacheKeyFilter.m; sourceTree = ""; }; 328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCacheSerializer.h; sourceTree = ""; }; @@ -1637,9 +1637,9 @@ 32FDE87A2088871B008D7530 /* MKAnnotationView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MKAnnotationView+WebCache.m"; sourceTree = ""; }; 32FDE87B2088871B008D7530 /* MKAnnotationView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MKAnnotationView+WebCache.h"; sourceTree = ""; }; 32FDE88520888726008D7530 /* UIImage+WebP.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+WebP.m"; sourceTree = ""; }; - 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageWebPCoder.h; sourceTree = ""; }; + 32FDE88620888726008D7530 /* SDImageWebPCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageWebPCoder.h; sourceTree = ""; }; 32FDE88720888726008D7530 /* UIImage+WebP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+WebP.h"; sourceTree = ""; }; - 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageWebPCoder.m; sourceTree = ""; }; + 32FDE88820888726008D7530 /* SDImageWebPCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageWebPCoder.m; sourceTree = ""; }; 32FDE8A4208887A6008D7530 /* SDWebImage.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = SDWebImage.modulemap; sourceTree = ""; }; 4314D1991D0E0E3B004B36C9 /* libSDWebImage watchOS static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libSDWebImage watchOS static.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 431BB7031D06D2C1006A3455 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1797,8 +1797,8 @@ 80377E841F2F66D000F89830 /* vp8li_dec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vp8li_dec.h; sourceTree = ""; }; 80377E851F2F66D000F89830 /* webp_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = webp_dec.c; sourceTree = ""; }; 80377E861F2F66D000F89830 /* webpi_dec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = webpi_dec.h; sourceTree = ""; }; - 807A12261F89636300EC2A9B /* SDWebImageCodersManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCodersManager.h; sourceTree = ""; }; - 807A12271F89636300EC2A9B /* SDWebImageCodersManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCodersManager.m; sourceTree = ""; }; + 807A12261F89636300EC2A9B /* SDImageCodersManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageCodersManager.h; sourceTree = ""; }; + 807A12271F89636300EC2A9B /* SDImageCodersManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageCodersManager.m; sourceTree = ""; }; A18A6CC5172DC28500419892 /* UIImage+GIF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+GIF.h"; sourceTree = ""; }; A18A6CC6172DC28500419892 /* UIImage+GIF.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+GIF.m"; sourceTree = ""; }; AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+WebCacheOperation.h"; sourceTree = ""; }; @@ -1869,16 +1869,16 @@ 321E60831F38E88F00405457 /* Decoder */ = { isa = PBXGroup; children = ( - 807A12261F89636300EC2A9B /* SDWebImageCodersManager.h */, - 807A12271F89636300EC2A9B /* SDWebImageCodersManager.m */, + 807A12261F89636300EC2A9B /* SDImageCodersManager.h */, + 807A12271F89636300EC2A9B /* SDImageCodersManager.m */, 321E60841F38E8C800405457 /* SDImageCoder.h */, 321E60851F38E8C800405457 /* SDImageCoder.m */, - 321E60921F38E8ED00405457 /* SDWebImageImageIOCoder.h */, - 321E60931F38E8ED00405457 /* SDWebImageImageIOCoder.m */, - 321E60A01F38E8F600405457 /* SDWebImageGIFCoder.h */, - 321E60A11F38E8F600405457 /* SDWebImageGIFCoder.m */, - 327054D2206CD8B3006EA328 /* SDWebImageAPNGCoder.h */, - 327054D3206CD8B3006EA328 /* SDWebImageAPNGCoder.m */, + 321E60921F38E8ED00405457 /* SDImageIOCoder.h */, + 321E60931F38E8ED00405457 /* SDImageIOCoder.m */, + 321E60A01F38E8F600405457 /* SDImageGIFCoder.h */, + 321E60A11F38E8F600405457 /* SDImageGIFCoder.m */, + 327054D2206CD8B3006EA328 /* SDImageAPNGCoder.h */, + 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */, 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */, 3290FA031FA478AF0047D20C /* SDWebImageFrame.m */, 32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */, @@ -1996,8 +1996,8 @@ children = ( 32FDE88720888726008D7530 /* UIImage+WebP.h */, 32FDE88520888726008D7530 /* UIImage+WebP.m */, - 32FDE88620888726008D7530 /* SDWebImageWebPCoder.h */, - 32FDE88820888726008D7530 /* SDWebImageWebPCoder.m */, + 32FDE88620888726008D7530 /* SDImageWebPCoder.h */, + 32FDE88820888726008D7530 /* SDImageWebPCoder.m */, ); path = WebP; sourceTree = ""; @@ -2404,14 +2404,14 @@ 4369C27A1D9807EC007E863A /* UIView+WebCache.h in Headers */, 32F21B5420788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 80377DCC1F2F66A700F89830 /* lossless_common.h in Headers */, - 321E60971F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, + 321E60971F38E8ED00405457 /* SDImageIOCoder.h in Headers */, 43A918671D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, - 327054D7206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, + 327054D7206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, 431739571CDFC8B70008FEB9 /* encode.h in Headers */, 323F8B711F38EF770092B609 /* delta_palettization_enc.h in Headers */, 3290FA071FA478AF0047D20C /* SDWebImageFrame.h in Headers */, 324DF4B7200A14DC008A84CC /* SDWebImageDefine.h in Headers */, - 807A122B1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, + 807A122B1F89636300EC2A9B /* SDImageCodersManager.h in Headers */, 80377EC61F2F66D500F89830 /* webpi_dec.h in Headers */, 80377C591F2F666300F89830 /* random_utils.h in Headers */, 80377DD91F2F66A700F89830 /* lossless.h in Headers */, @@ -2432,7 +2432,7 @@ 00733A701BC4880E00A5A117 /* UIImageView+HighlightedWebCache.h in Headers */, 323F8BDB1F38EF770092B609 /* vp8i_enc.h in Headers */, 80377C461F2F666300F89830 /* bit_reader_inl_utils.h in Headers */, - 32FDE89220888726008D7530 /* SDWebImageWebPCoder.h in Headers */, + 32FDE89220888726008D7530 /* SDImageWebPCoder.h in Headers */, 00733A671BC4880E00A5A117 /* SDImageCache.h in Headers */, 00733A711BC4880E00A5A117 /* UIImageView+WebCache.h in Headers */, 00733A631BC4880E00A5A117 /* SDWebImageCompat.h in Headers */, @@ -2452,7 +2452,7 @@ 00733A6A1BC4880E00A5A117 /* SDWebImagePrefetcher.h in Headers */, 00733A641BC4880E00A5A117 /* SDWebImageOperation.h in Headers */, 32484766201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, - 321E60A51F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, + 321E60A51F38E8F600405457 /* SDImageGIFCoder.h in Headers */, 32CF1C0A1FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, 80377C4D1F2F666300F89830 /* endian_inl_utils.h in Headers */, 431739581CDFC8B70008FEB9 /* format_constants.h in Headers */, @@ -2494,15 +2494,15 @@ 80377C1D1F2F666300F89830 /* huffman_encode_utils.h in Headers */, 80377E9A1F2F66D400F89830 /* common_dec.h in Headers */, 32D1221F2080B2EB003685A3 /* SDImageCacheDefine.h in Headers */, - 327054D5206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, + 327054D5206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, 328BB6AB2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 32B9B538206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 80377C231F2F666300F89830 /* quant_levels_utils.h in Headers */, 321E60BF1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 80377EA61F2F66D400F89830 /* webpi_dec.h in Headers */, - 807A12291F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, + 807A12291F89636300EC2A9B /* SDImageCodersManager.h in Headers */, 32F7C0852030719600873181 /* UIImage+Transform.h in Headers */, - 32FDE89020888726008D7530 /* SDWebImageWebPCoder.h in Headers */, + 32FDE89020888726008D7530 /* SDImageWebPCoder.h in Headers */, 80377C141F2F666300F89830 /* bit_reader_utils.h in Headers */, 328BB69D2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, 323F8C0F1F38EF770092B609 /* muxi.h in Headers */, @@ -2525,7 +2525,7 @@ 80377EA21F2F66D400F89830 /* vp8i_dec.h in Headers */, 320CAE162086F50500CFFC80 /* SDWebImageError.h in Headers */, 3248476A201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, - 321E60951F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, + 321E60951F38E8ED00405457 /* SDImageIOCoder.h in Headers */, 80377C211F2F666300F89830 /* quant_levels_dec_utils.h in Headers */, 4314D1721D0E0E3B004B36C9 /* SDWebImageCompat.h in Headers */, 32484776201775F600AF9E5A /* SDAnimatedImage.h in Headers */, @@ -2551,7 +2551,7 @@ 323F8BE51F38EF770092B609 /* vp8li_enc.h in Headers */, 324DF4B5200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 80377C191F2F666300F89830 /* endian_inl_utils.h in Headers */, - 321E60A31F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, + 321E60A31F38E8F600405457 /* SDImageGIFCoder.h in Headers */, 32FDE8A320888789008D7530 /* SDWebImage.h in Headers */, 32F21B5220788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 4369C2781D9807EC007E863A /* UIView+WebCache.h in Headers */, @@ -2618,7 +2618,7 @@ 80377E031F2F66A800F89830 /* dsp.h in Headers */, 80377C661F2F666400F89830 /* color_cache_utils.h in Headers */, 3290FA081FA478AF0047D20C /* SDWebImageFrame.h in Headers */, - 321E60A61F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, + 321E60A61F38E8F600405457 /* SDImageGIFCoder.h in Headers */, 431BB6E71D06D2C1006A3455 /* SDWebImageCompat.h in Headers */, 80377E211F2F66A800F89830 /* neon.h in Headers */, 80377C711F2F666400F89830 /* quant_levels_utils.h in Headers */, @@ -2642,10 +2642,10 @@ 32C0FDE52013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 80377ED61F2F66D500F89830 /* webpi_dec.h in Headers */, 323F8BE81F38EF770092B609 /* vp8li_enc.h in Headers */, - 32FDE89320888726008D7530 /* SDWebImageWebPCoder.h in Headers */, + 32FDE89320888726008D7530 /* SDImageWebPCoder.h in Headers */, 323F8B8A1F38EF770092B609 /* histogram_enc.h in Headers */, 80377E1E1F2F66A800F89830 /* lossless.h in Headers */, - 321E60981F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, + 321E60981F38E8ED00405457 /* SDImageIOCoder.h in Headers */, 328BB6D12082581100760D6C /* SDMemoryCache.h in Headers */, 4369C27B1D9807EC007E863A /* UIView+WebCache.h in Headers */, 80377ED11F2F66D500F89830 /* vp8_dec.h in Headers */, @@ -2662,7 +2662,7 @@ 431BB6F61D06D2C1006A3455 /* UIImage+MultiFormat.h in Headers */, 320CAE192086F50500CFFC80 /* SDWebImageError.h in Headers */, 32F21B5520788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, - 807A122C1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, + 807A122C1F89636300EC2A9B /* SDImageCodersManager.h in Headers */, 323F8BFA1F38EF770092B609 /* animi.h in Headers */, 431BB6F91D06D2C1006A3455 /* UIImage+GIF.h in Headers */, 32F7C0732030114C00873181 /* SDWebImageTransformer.h in Headers */, @@ -2673,7 +2673,7 @@ 323F8BDC1F38EF770092B609 /* vp8i_enc.h in Headers */, 80377ED21F2F66D500F89830 /* vp8i_dec.h in Headers */, 32484779201775F600AF9E5A /* SDAnimatedImage.h in Headers */, - 327054D8206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, + 327054D8206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, 43A918681D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2684,7 +2684,7 @@ files = ( 80377C7E1F2F666400F89830 /* bit_writer_utils.h in Headers */, 80377ED81F2F66D500F89830 /* alphai_dec.h in Headers */, - 321E60A71F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, + 321E60A71F38E8F600405457 /* SDImageGIFCoder.h in Headers */, 324DF4B9200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 32F7C0892030719600873181 /* UIImage+Transform.h in Headers */, 80377EDA1F2F66D500F89830 /* common_dec.h in Headers */, @@ -2702,9 +2702,9 @@ 80377C8D1F2F666400F89830 /* random_utils.h in Headers */, 4397D2C31D0DDD8C00BB2784 /* SDWebImageManager.h in Headers */, 323F8B551F38EF770092B609 /* backward_references_enc.h in Headers */, - 327054D9206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, + 327054D9206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, 80377C811F2F666400F89830 /* endian_inl_utils.h in Headers */, - 321E60991F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, + 321E60991F38E8ED00405457 /* SDImageIOCoder.h in Headers */, 323F8B8B1F38EF770092B609 /* histogram_enc.h in Headers */, 4397D2C41D0DDD8C00BB2784 /* SDImageCache.h in Headers */, 3248476E201775F600AF9E5A /* SDAnimatedImageView.h in Headers */, @@ -2727,7 +2727,7 @@ 329A185E1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 320224BB203979BA00E9F285 /* SDAnimatedImageRep.h in Headers */, 328BB6C62082581100760D6C /* SDDiskCache.h in Headers */, - 32FDE89420888726008D7530 /* SDWebImageWebPCoder.h in Headers */, + 32FDE89420888726008D7530 /* SDImageWebPCoder.h in Headers */, 80377E761F2F66A800F89830 /* yuv.h in Headers */, 80377C7A1F2F666400F89830 /* bit_reader_inl_utils.h in Headers */, 80377E631F2F66A800F89830 /* lossless.h in Headers */, @@ -2771,7 +2771,7 @@ 4397D2EB1D0DDD8C00BB2784 /* NSData+ImageContentType.h in Headers */, 80377C851F2F666400F89830 /* huffman_encode_utils.h in Headers */, 321DB3612011D4D70015D2CB /* NSButton+WebCache.h in Headers */, - 807A122D1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, + 807A122D1F89636300EC2A9B /* SDImageCodersManager.h in Headers */, 4397D2ED1D0DDD8C00BB2784 /* mux_types.h in Headers */, 80377C831F2F666400F89830 /* filters_utils.h in Headers */, 80377E651F2F66A800F89830 /* msa_macro.h in Headers */, @@ -2801,15 +2801,15 @@ 4369C2791D9807EC007E863A /* UIView+WebCache.h in Headers */, 32F21B5320788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 80377D871F2F66A700F89830 /* lossless_common.h in Headers */, - 321E60961F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, + 321E60961F38E8ED00405457 /* SDImageIOCoder.h in Headers */, 4A2CAE041AB4BB5400B6BC39 /* SDWebImage.h in Headers */, - 327054D6206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, + 327054D6206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, 431739511CDFC8B70008FEB9 /* format_constants.h in Headers */, 43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 323F8B701F38EF770092B609 /* delta_palettization_enc.h in Headers */, 3290FA061FA478AF0047D20C /* SDWebImageFrame.h in Headers */, 324DF4B6200A14DC008A84CC /* SDWebImageDefine.h in Headers */, - 807A122A1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, + 807A122A1F89636300EC2A9B /* SDImageCodersManager.h in Headers */, 80377EB61F2F66D400F89830 /* webpi_dec.h in Headers */, 4A2CAE211AB4BB7000B6BC39 /* SDWebImageManager.h in Headers */, 80377D941F2F66A700F89830 /* lossless.h in Headers */, @@ -2828,7 +2828,7 @@ 323F8B641F38EF770092B609 /* cost_enc.h in Headers */, 328BB6C32082581100760D6C /* SDDiskCache.h in Headers */, 4A2CAE1D1AB4BB6800B6BC39 /* SDWebImageDownloaderOperation.h in Headers */, - 32FDE89120888726008D7530 /* SDWebImageWebPCoder.h in Headers */, + 32FDE89120888726008D7530 /* SDImageWebPCoder.h in Headers */, 323F8BDA1F38EF770092B609 /* vp8i_enc.h in Headers */, 4317394E1CDFC8B70008FEB9 /* decode.h in Headers */, 80377C2C1F2F666300F89830 /* bit_reader_inl_utils.h in Headers */, @@ -2850,7 +2850,7 @@ 4A2CAE1A1AB4BB6400B6BC39 /* SDWebImageOperation.h in Headers */, 80377C331F2F666300F89830 /* endian_inl_utils.h in Headers */, 32484765201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, - 321E60A41F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, + 321E60A41F38E8F600405457 /* SDImageGIFCoder.h in Headers */, 32CF1C091FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */, 4A2CAE1B1AB4BB6800B6BC39 /* SDWebImageDownloader.h in Headers */, 431739501CDFC8B70008FEB9 /* encode.h in Headers */, @@ -2894,7 +2894,7 @@ 323F8C0E1F38EF770092B609 /* muxi.h in Headers */, 325312C8200F09910046BF1E /* SDWebImageTransition.h in Headers */, 32C0FDE12013426C001B8F2D /* SDWebImageIndicator.h in Headers */, - 321E60A21F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */, + 321E60A21F38E8F600405457 /* SDImageGIFCoder.h in Headers */, 5D5B9142188EE8DD006D06BD /* NSData+ImageContentType.h in Headers */, 80377BFE1F2F665300F89830 /* color_cache_utils.h in Headers */, 328BB6C12082581100760D6C /* SDDiskCache.h in Headers */, @@ -2907,12 +2907,12 @@ 3290FA041FA478AF0047D20C /* SDWebImageFrame.h in Headers */, 80377D1D1F2F66A100F89830 /* yuv.h in Headers */, 43CE75D01CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */, - 807A12281F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */, + 807A12281F89636300EC2A9B /* SDImageCodersManager.h in Headers */, 32B9B537206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 80377C051F2F665300F89830 /* huffman_utils.h in Headers */, 80377E881F2F66D000F89830 /* alphai_dec.h in Headers */, 32484775201775F600AF9E5A /* SDAnimatedImage.h in Headers */, - 321E60941F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */, + 321E60941F38E8ED00405457 /* SDImageIOCoder.h in Headers */, 431738BD1CDFC2660008FEB9 /* decode.h in Headers */, 80377D0B1F2F66A100F89830 /* mips_macro.h in Headers */, 329A18591FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, @@ -2938,7 +2938,7 @@ 80377C0B1F2F665300F89830 /* random_utils.h in Headers */, 80377E921F2F66D000F89830 /* vp8i_dec.h in Headers */, 5376131F155AD0D5005750A4 /* UIButton+WebCache.h in Headers */, - 327054D4206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */, + 327054D4206CD8B3006EA328 /* SDImageAPNGCoder.h in Headers */, 53761320155AD0D5005750A4 /* UIImageView+WebCache.h in Headers */, 328BB69C2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, 530E49E816464C25002868E7 /* SDWebImageOperation.h in Headers */, @@ -2955,7 +2955,7 @@ 323F8B621F38EF770092B609 /* cost_enc.h in Headers */, 43CE75761CFE9427006C64D0 /* FLAnimatedImage.h in Headers */, 323F8BE41F38EF770092B609 /* vp8li_enc.h in Headers */, - 32FDE88F20888726008D7530 /* SDWebImageWebPCoder.h in Headers */, + 32FDE88F20888726008D7530 /* SDImageWebPCoder.h in Headers */, 320CAE152086F50500CFFC80 /* SDWebImageError.h in Headers */, 323F8B861F38EF770092B609 /* histogram_enc.h in Headers */, 321B37812083290E00C0EA77 /* SDWebImageLoader.h in Headers */, @@ -3271,9 +3271,9 @@ 323F8B991F38EF770092B609 /* near_lossless_enc.c in Sources */, 80377DE81F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */, 80377EC31F2F66D500F89830 /* vp8l_dec.c in Sources */, - 327054DD206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */, + 327054DD206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, 325312D1200F09910046BF1E /* SDWebImageTransition.m in Sources */, - 321E609D1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */, + 321E609D1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, 323F8B9F1F38EF770092B609 /* picture_csp_enc.c in Sources */, 43C892A31D9D6DDD0022038D /* demux.c in Sources */, 00733A611BC4880000A5A117 /* UIImageView+WebCache.m in Sources */, @@ -3298,7 +3298,7 @@ 80377DAA1F2F66A700F89830 /* alpha_processing_sse2.c in Sources */, 43A9186E1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, 80377C471F2F666300F89830 /* bit_reader_utils.c in Sources */, - 321E60AB1F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */, + 321E60AB1F38E8F600405457 /* SDImageGIFCoder.m in Sources */, 323F8BD51F38EF770092B609 /* tree_enc.c in Sources */, 80377DBB1F2F66A700F89830 /* dec_sse2.c in Sources */, 323F8B831F38EF770092B609 /* histogram_enc.c in Sources */, @@ -3322,7 +3322,7 @@ 321B378A2083290E00C0EA77 /* SDWebImageLoader.m in Sources */, 32484772201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 323F8C1D1F38EF770092B609 /* muxread.c in Sources */, - 807A12311F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */, + 807A12311F89636300EC2A9B /* SDImageCodersManager.m in Sources */, 80377C491F2F666300F89830 /* bit_writer_utils.c in Sources */, 323F8B471F38EF770092B609 /* analysis_enc.c in Sources */, 80377DB51F2F66A700F89830 /* cpu.c in Sources */, @@ -3333,7 +3333,7 @@ 80377EC01F2F66D500F89830 /* vp8_dec.c in Sources */, 80377C521F2F666300F89830 /* huffman_utils.c in Sources */, 80377DD81F2F66A700F89830 /* lossless.c in Sources */, - 32FDE89E20888726008D7530 /* SDWebImageWebPCoder.m in Sources */, + 32FDE89E20888726008D7530 /* SDImageWebPCoder.m in Sources */, 80377DE11F2F66A700F89830 /* rescaler_sse2.c in Sources */, 324DF4BD200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 80377DAC1F2F66A700F89830 /* alpha_processing.c in Sources */, @@ -3422,9 +3422,9 @@ 3290FA0B1FA478AF0047D20C /* SDWebImageFrame.m in Sources */, 80377C2A1F2F666300F89830 /* utils.c in Sources */, 323F8B4B1F38EF770092B609 /* backward_references_enc.c in Sources */, - 807A122F1F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */, + 807A122F1F89636300EC2A9B /* SDImageCodersManager.m in Sources */, 4314D1361D0E0E3B004B36C9 /* SDWebImageManager.m in Sources */, - 321E609B1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */, + 321E609B1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, 80377D4E1F2F66A700F89830 /* lossless.c in Sources */, 80377D351F2F66A700F89830 /* enc_avx2.c in Sources */, 80377D201F2F66A700F89830 /* alpha_processing_sse2.c in Sources */, @@ -3488,7 +3488,7 @@ 80377C221F2F666300F89830 /* quant_levels_utils.c in Sources */, 80377D2E1F2F66A700F89830 /* dec_mips32.c in Sources */, 323F8BD31F38EF770092B609 /* tree_enc.c in Sources */, - 327054DB206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */, + 327054DB206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, 80377D5C1F2F66A700F89830 /* upsampling_sse2.c in Sources */, 323F8BC71F38EF770092B609 /* syntax_enc.c in Sources */, 328BB6D42082581100760D6C /* SDMemoryCache.m in Sources */, @@ -3508,7 +3508,7 @@ 80377E971F2F66D400F89830 /* alpha_dec.c in Sources */, 323F8B691F38EF770092B609 /* delta_palettization_enc.c in Sources */, 4314D1501D0E0E3B004B36C9 /* UIView+WebCacheOperation.m in Sources */, - 321E60A91F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */, + 321E60A91F38E8F600405457 /* SDImageGIFCoder.m in Sources */, 80377D5A1F2F66A700F89830 /* upsampling_msa.c in Sources */, 80377D491F2F66A700F89830 /* lossless_enc.c in Sources */, 80377C171F2F666300F89830 /* color_cache_utils.c in Sources */, @@ -3518,7 +3518,7 @@ 80377D5D1F2F66A700F89830 /* upsampling.c in Sources */, 80377D251F2F66A700F89830 /* argb.c in Sources */, 80377D281F2F66A700F89830 /* cost_mips32.c in Sources */, - 32FDE89C20888726008D7530 /* SDWebImageWebPCoder.m in Sources */, + 32FDE89C20888726008D7530 /* SDImageWebPCoder.m in Sources */, 323F8BF11F38EF770092B609 /* anim_encode.c in Sources */, 4314D1551D0E0E3B004B36C9 /* UIImageView+HighlightedWebCache.m in Sources */, 80377E991F2F66D400F89830 /* buffer_dec.c in Sources */, @@ -3590,9 +3590,9 @@ 80377E2F1F2F66A800F89830 /* yuv_sse2.c in Sources */, 431BB6AA1D06D2C1006A3455 /* SDWebImageManager.m in Sources */, 323F8B4E1F38EF770092B609 /* backward_references_enc.c in Sources */, - 807A12321F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */, + 807A12321F89636300EC2A9B /* SDImageCodersManager.m in Sources */, 80377C761F2F666400F89830 /* thread_utils.c in Sources */, - 321E609E1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */, + 321E609E1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, 80377E1D1F2F66A800F89830 /* lossless.c in Sources */, 80377E041F2F66A800F89830 /* enc_avx2.c in Sources */, 80377DEF1F2F66A800F89830 /* alpha_processing_sse2.c in Sources */, @@ -3654,7 +3654,7 @@ 80377E301F2F66A800F89830 /* yuv.c in Sources */, 43A9186F1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, 323F8BD61F38EF770092B609 /* tree_enc.c in Sources */, - 327054DE206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */, + 327054DE206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, 80377DFD1F2F66A800F89830 /* dec_mips32.c in Sources */, 323F8BCA1F38EF770092B609 /* syntax_enc.c in Sources */, 328BB6D72082581100760D6C /* SDMemoryCache.m in Sources */, @@ -3674,7 +3674,7 @@ 80377EC71F2F66D500F89830 /* alpha_dec.c in Sources */, 323F8B6C1F38EF770092B609 /* delta_palettization_enc.c in Sources */, 80377C681F2F666400F89830 /* filters_utils.c in Sources */, - 321E60AC1F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */, + 321E60AC1F38E8F600405457 /* SDImageGIFCoder.m in Sources */, 80377E291F2F66A800F89830 /* upsampling_msa.c in Sources */, 80377E181F2F66A800F89830 /* lossless_enc.c in Sources */, 431BB6C01D06D2C1006A3455 /* SDImageCache.m in Sources */, @@ -3684,7 +3684,7 @@ 80377E2C1F2F66A800F89830 /* upsampling.c in Sources */, 80377DF41F2F66A800F89830 /* argb.c in Sources */, 80377DF71F2F66A800F89830 /* cost_mips32.c in Sources */, - 32FDE89F20888726008D7530 /* SDWebImageWebPCoder.m in Sources */, + 32FDE89F20888726008D7530 /* SDImageWebPCoder.m in Sources */, 323F8BF41F38EF770092B609 /* anim_encode.c in Sources */, 80377C6E1F2F666400F89830 /* quant_levels_dec_utils.c in Sources */, 80377EC91F2F66D500F89830 /* buffer_dec.c in Sources */, @@ -3743,7 +3743,7 @@ 80377E581F2F66A800F89830 /* lossless_enc_mips32.c in Sources */, 4397D28F1D0DDD8C00BB2784 /* SDWebImageDownloaderOperation.m in Sources */, 323F8BB91F38EF770092B609 /* picture_tools_enc.c in Sources */, - 32FDE8A020888726008D7530 /* SDWebImageWebPCoder.m in Sources */, + 32FDE8A020888726008D7530 /* SDImageWebPCoder.m in Sources */, 80377E451F2F66A800F89830 /* dec_sse2.c in Sources */, 80377E3F1F2F66A800F89830 /* cpu.c in Sources */, 80377E4C1F2F66A800F89830 /* enc_msa.c in Sources */, @@ -3769,7 +3769,7 @@ 4397D2921D0DDD8C00BB2784 /* SDWebImagePrefetcher.m in Sources */, 323F8BBF1F38EF770092B609 /* predictor_enc.c in Sources */, 32FDE88E20888726008D7530 /* UIImage+WebP.m in Sources */, - 807A12331F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */, + 807A12331F89636300EC2A9B /* SDImageCodersManager.m in Sources */, 323F8BD11F38EF770092B609 /* token_enc.c in Sources */, 323F8B4F1F38EF770092B609 /* backward_references_enc.c in Sources */, 80377E4D1F2F66A800F89830 /* enc_neon.c in Sources */, @@ -3815,8 +3815,8 @@ 80377ED91F2F66D500F89830 /* buffer_dec.c in Sources */, 4397D2A11D0DDD8C00BB2784 /* SDWebImageManager.m in Sources */, 323F8BCB1F38EF770092B609 /* syntax_enc.c in Sources */, - 321E60AD1F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */, - 327054DF206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */, + 321E60AD1F38E8F600405457 /* SDImageGIFCoder.m in Sources */, + 327054DF206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, 80377E341F2F66A800F89830 /* alpha_processing_sse2.c in Sources */, 4397D2A61D0DDD8C00BB2784 /* SDWebImageCompat.m in Sources */, 80377E6F1F2F66A800F89830 /* upsampling_neon.c in Sources */, @@ -3831,7 +3831,7 @@ 80377E321F2F66A800F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, 323F8B611F38EF770092B609 /* cost_enc.c in Sources */, 80377EDE1F2F66D500F89830 /* quant_dec.c in Sources */, - 321E609F1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */, + 321E609F1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, 323F8B5B1F38EF770092B609 /* config_enc.c in Sources */, 80377E361F2F66A800F89830 /* alpha_processing.c in Sources */, 80377E351F2F66A800F89830 /* alpha_processing_sse41.c in Sources */, @@ -3940,9 +3940,9 @@ 323F8B981F38EF770092B609 /* near_lossless_enc.c in Sources */, 80377D6F1F2F66A700F89830 /* cost.c in Sources */, 80377EB31F2F66D400F89830 /* vp8l_dec.c in Sources */, - 327054DC206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */, + 327054DC206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, 325312D0200F09910046BF1E /* SDWebImageTransition.m in Sources */, - 321E609C1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */, + 321E609C1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, 323F8B9E1F38EF770092B609 /* picture_csp_enc.c in Sources */, 80377D9E1F2F66A700F89830 /* upsampling_mips_dsp_r2.c in Sources */, 80377DA31F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */, @@ -3966,7 +3966,7 @@ 80377D771F2F66A700F89830 /* dec_sse41.c in Sources */, 80377D891F2F66A700F89830 /* lossless_enc_mips32.c in Sources */, 80377D861F2F66A700F89830 /* filters.c in Sources */, - 321E60AA1F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */, + 321E60AA1F38E8F600405457 /* SDImageGIFCoder.m in Sources */, 323F8BD41F38EF770092B609 /* tree_enc.c in Sources */, 80377D651F2F66A700F89830 /* alpha_processing_sse2.c in Sources */, 323F8B821F38EF770092B609 /* histogram_enc.c in Sources */, @@ -3992,7 +3992,7 @@ 32484771201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 80377C3C1F2F666300F89830 /* quant_levels_utils.c in Sources */, 323F8C1C1F38EF770092B609 /* muxread.c in Sources */, - 807A12301F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */, + 807A12301F89636300EC2A9B /* SDImageCodersManager.m in Sources */, 80377C2F1F2F666300F89830 /* bit_writer_utils.c in Sources */, 323F8B461F38EF770092B609 /* analysis_enc.c in Sources */, 80377D8C1F2F66A700F89830 /* lossless_enc_sse2.c in Sources */, @@ -4003,7 +4003,7 @@ 80377D911F2F66A700F89830 /* lossless_neon.c in Sources */, 80377EB01F2F66D400F89830 /* vp8_dec.c in Sources */, 80377C381F2F666300F89830 /* huffman_utils.c in Sources */, - 32FDE89D20888726008D7530 /* SDWebImageWebPCoder.m in Sources */, + 32FDE89D20888726008D7530 /* SDImageWebPCoder.m in Sources */, 80377C3A1F2F666300F89830 /* quant_levels_dec_utils.c in Sources */, 324DF4BC200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 80377D931F2F66A700F89830 /* lossless.c in Sources */, @@ -4109,8 +4109,8 @@ 32F7C07E2030719600873181 /* UIImage+Transform.m in Sources */, 80377CE51F2F66A100F89830 /* cost.c in Sources */, 80377E931F2F66D000F89830 /* vp8l_dec.c in Sources */, - 321E609A1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */, - 327054DA206CD8B3006EA328 /* SDWebImageAPNGCoder.m in Sources */, + 321E609A1F38E8ED00405457 /* SDImageIOCoder.m in Sources */, + 327054DA206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */, 325312CE200F09910046BF1E /* SDWebImageTransition.m in Sources */, 323F8B9C1F38EF770092B609 /* picture_csp_enc.c in Sources */, 80377D141F2F66A100F89830 /* upsampling_mips_dsp_r2.c in Sources */, @@ -4136,7 +4136,7 @@ 80377CED1F2F66A100F89830 /* dec_sse41.c in Sources */, 80377CFF1F2F66A100F89830 /* lossless_enc_mips32.c in Sources */, 80377CFC1F2F66A100F89830 /* filters.c in Sources */, - 321E60A81F38E8F600405457 /* SDWebImageGIFCoder.m in Sources */, + 321E60A81F38E8F600405457 /* SDImageGIFCoder.m in Sources */, 323F8BD21F38EF770092B609 /* tree_enc.c in Sources */, 80377CDB1F2F66A100F89830 /* alpha_processing_sse2.c in Sources */, 323F8B801F38EF770092B609 /* histogram_enc.c in Sources */, @@ -4161,7 +4161,7 @@ 321B37872083290E00C0EA77 /* SDWebImageLoader.m in Sources */, 3248476F201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 323F8C1A1F38EF770092B609 /* muxread.c in Sources */, - 807A122E1F89636300EC2A9B /* SDWebImageCodersManager.m in Sources */, + 807A122E1F89636300EC2A9B /* SDImageCodersManager.m in Sources */, 80377BFB1F2F665300F89830 /* bit_writer_utils.c in Sources */, 323F8B441F38EF770092B609 /* analysis_enc.c in Sources */, 80377D021F2F66A100F89830 /* lossless_enc_sse2.c in Sources */, @@ -4173,7 +4173,7 @@ 80377E901F2F66D000F89830 /* vp8_dec.c in Sources */, 80377C041F2F665300F89830 /* huffman_utils.c in Sources */, 80377C061F2F665300F89830 /* quant_levels_dec_utils.c in Sources */, - 32FDE89B20888726008D7530 /* SDWebImageWebPCoder.m in Sources */, + 32FDE89B20888726008D7530 /* SDImageWebPCoder.m in Sources */, 80377D091F2F66A100F89830 /* lossless.c in Sources */, 324DF4BA200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 80377D121F2F66A100F89830 /* rescaler_sse2.c in Sources */, diff --git a/SDWebImage/SDAnimatedImage.h b/SDWebImage/SDAnimatedImage.h index 2c829f29..4a8a5270 100644 --- a/SDWebImage/SDAnimatedImage.h +++ b/SDWebImage/SDAnimatedImage.h @@ -11,7 +11,7 @@ /** - This is the protocol for SDAnimatedImage class only but not for SDWebImageAnimatedCoder. If you want to provide a custom animated image class with full advanced function, you can conform to this instead of the base protocol. + This is the protocol for SDAnimatedImage class only but not for SDAnimatedImageCoder. If you want to provide a custom animated image class with full advanced function, you can conform to this instead of the base protocol. */ @protocol SDAnimatedImage @@ -20,7 +20,7 @@ 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. However, for progressive image decoding, we will use this with animated coder which conforms to `SDProgressiveImageCoder` as well instead. - @param animatedCoder An animated coder which conform `SDWebImageAnimatedCoder` protocol + @param animatedCoder An animated coder which conform `SDAnimatedImageCoder` protocol @param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property. @return An initialized object */ diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index b9bb6a5f..28e6dcde 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -10,7 +10,7 @@ #import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" #import "SDImageCoder.h" -#import "SDWebImageCodersManager.h" +#import "SDImageCodersManager.h" #import "SDWebImageFrame.h" #define LOCK(...) dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER); \ @@ -286,7 +286,7 @@ static NSArray *SDBundlePreferredScales() { } data = [data copy]; // avoid mutable data id animatedCoder = nil; - for (idcoder in [SDWebImageCodersManager sharedManager].coders) { + for (idcoder in [SDImageCodersManager sharedManager].coders) { if ([coder conformsToProtocol:@protocol(SDAnimatedImageCoder)]) { if ([coder canDecodeFromData:data]) { animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data options:@{SDImageCoderDecodeScaleFactor : @(scale)}]; @@ -357,7 +357,7 @@ static NSArray *SDBundlePreferredScales() { return self; } id animatedCoder = nil; - for (idcoder in [SDWebImageCodersManager sharedManager].coders) { + for (idcoder in [SDImageCodersManager sharedManager].coders) { if ([coder conformsToProtocol:@protocol(SDAnimatedImageCoder)]) { if ([coder canDecodeFromData:animatedImageData]) { animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:animatedImageData options:@{SDImageCoderDecodeScaleFactor : @(scale)}]; diff --git a/SDWebImage/SDAnimatedImageRep.h b/SDWebImage/SDAnimatedImageRep.h index 32da091b..929d82af 100644 --- a/SDWebImage/SDAnimatedImageRep.h +++ b/SDWebImage/SDAnimatedImageRep.h @@ -11,8 +11,8 @@ #if SD_MAC // A subclass of `NSBitmapImageRep` to fix that GIF loop count issue because `NSBitmapImageRep` will reset `NSImageCurrentFrameDuration` by using `kCGImagePropertyGIFDelayTime` but not `kCGImagePropertyGIFUnclampedDelayTime`. -// Built in GIF coder use this instead of `NSBitmapImageRep` for better GIF rendering. If you do not want this, only enable `SDWebImageImageIOCoder`, which just call `NSImage` API and actually use `NSBitmapImageRep` for GIF image. -// This also support APNG format using `SDWebImageAPNGCoder`. Which provide full alpha-channel support and the correct duration match the `kCGImagePropertyAPNGUnclampedDelayTime`. +// Built in GIF coder use this instead of `NSBitmapImageRep` for better GIF rendering. If you do not want this, only enable `SDImageIOCoder`, which just call `NSImage` API and actually use `NSBitmapImageRep` for GIF image. +// This also support APNG format using `SDImageAPNGCoder`. Which provide full alpha-channel support and the correct duration match the `kCGImagePropertyAPNGUnclampedDelayTime`. @interface SDAnimatedImageRep : NSBitmapImageRep diff --git a/SDWebImage/SDAnimatedImageRep.m b/SDWebImage/SDAnimatedImageRep.m index e8b95cc9..1fc459e5 100644 --- a/SDWebImage/SDAnimatedImageRep.m +++ b/SDWebImage/SDAnimatedImageRep.m @@ -10,16 +10,16 @@ #if SD_MAC -#import "SDWebImageGIFCoder.h" -#import "SDWebImageAPNGCoder.h" +#import "SDImageGIFCoder.h" +#import "SDImageAPNGCoder.h" -@interface SDWebImageGIFCoder () +@interface SDImageGIFCoder () - (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source; @end -@interface SDWebImageAPNGCoder () +@interface SDImageAPNGCoder () - (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source; - (NSUInteger)sd_imageLoopCountWithSource:(CGImageSourceRef)source; @@ -64,7 +64,7 @@ // Do initilize about frame count, current frame/duration and loop count [self setProperty:NSImageFrameCount withValue:@(frameCount)]; [self setProperty:NSImageCurrentFrame withValue:@(0)]; - NSUInteger loopCount = [[SDWebImageAPNGCoder sharedCoder] sd_imageLoopCountWithSource:imageSource]; + NSUInteger loopCount = [[SDImageAPNGCoder sharedCoder] sd_imageLoopCountWithSource:imageSource]; [self setProperty:NSImageLoopCount withValue:@(loopCount)]; } } @@ -89,10 +89,10 @@ float frameDuration = 0; if (CFStringCompare(type, kUTTypeGIF, 0) == kCFCompareEqualTo) { // GIF - frameDuration = [[SDWebImageGIFCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource]; + frameDuration = [[SDImageGIFCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource]; } else if (CFStringCompare(type, kUTTypePNG, 0) == kCFCompareEqualTo) { // APNG - frameDuration = [[SDWebImageAPNGCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource]; + frameDuration = [[SDImageAPNGCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource]; } if (!frameDuration) { return; diff --git a/SDWebImage/SDWebImageAPNGCoder.h b/SDWebImage/SDImageAPNGCoder.h similarity index 68% rename from SDWebImage/SDWebImageAPNGCoder.h rename to SDWebImage/SDImageAPNGCoder.h index 489513c0..a674a95b 100644 --- a/SDWebImage/SDWebImageAPNGCoder.h +++ b/SDWebImage/SDImageAPNGCoder.h @@ -12,8 +12,8 @@ /** Built in coder using ImageIO that supports APNG encoding/decoding */ -@interface SDWebImageAPNGCoder : NSObject +@interface SDImageAPNGCoder : NSObject -@property (nonatomic, class, readonly, nonnull) SDWebImageAPNGCoder *sharedCoder; +@property (nonatomic, class, readonly, nonnull) SDImageAPNGCoder *sharedCoder; @end diff --git a/SDWebImage/SDWebImageAPNGCoder.m b/SDWebImage/SDImageAPNGCoder.m similarity index 98% rename from SDWebImage/SDWebImageAPNGCoder.m rename to SDWebImage/SDImageAPNGCoder.m index 5a2ac166..b62b633a 100644 --- a/SDWebImage/SDWebImageAPNGCoder.m +++ b/SDWebImage/SDImageAPNGCoder.m @@ -6,7 +6,7 @@ * file that was distributed with this source code. */ -#import "SDWebImageAPNGCoder.h" +#import "SDImageAPNGCoder.h" #import #import "NSData+ImageContentType.h" #import "UIImage+WebCache.h" @@ -31,7 +31,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef @implementation SDAPNGCoderFrame @end -@implementation SDWebImageAPNGCoder { +@implementation SDImageAPNGCoder { size_t _width, _height; CGImageSourceRef _imageSource; NSData *_imageData; @@ -63,10 +63,10 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef } + (instancetype)sharedCoder { - static SDWebImageAPNGCoder *coder; + static SDImageAPNGCoder *coder; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - coder = [[SDWebImageAPNGCoder alloc] init]; + coder = [[SDImageAPNGCoder alloc] init]; }); return coder; } @@ -315,7 +315,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef return image; } -#pragma mark - SDWebImageAnimatedCoder +#pragma mark - SDAnimatedImageCoder - (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data options:(nullable SDImageCoderOptions *)options { if (!data) { return nil; diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 175256ff..f556860a 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -11,7 +11,7 @@ #import "SDDiskCache.h" #import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" -#import "SDWebImageCodersManager.h" +#import "SDImageCodersManager.h" #import "SDWebImageTransformer.h" #import "SDWebImageCoderHelper.h" #import "SDAnimatedImage.h" @@ -182,7 +182,7 @@ } else { format = SDImageFormatJPEG; } - data = [[SDWebImageCodersManager sharedManager] encodedDataWithImage:image format:format options:nil]; + data = [[SDImageCodersManager sharedManager] encodedDataWithImage:image format:format options:nil]; } [self _storeImageDataToDisk:data forKey:key]; } diff --git a/SDWebImage/SDImageCacheDefine.m b/SDWebImage/SDImageCacheDefine.m index e3414c7a..9f01cf63 100644 --- a/SDWebImage/SDImageCacheDefine.m +++ b/SDWebImage/SDImageCacheDefine.m @@ -7,7 +7,7 @@ */ #import "SDImageCacheDefine.h" -#import "SDWebImageCodersManager.h" +#import "SDImageCodersManager.h" #import "SDWebImageCoderHelper.h" #import "SDAnimatedImage.h" #import "UIImage+WebCache.h" @@ -33,7 +33,7 @@ UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSS } } if (!image) { - image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}]; + image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}]; } if (image) { BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; diff --git a/SDWebImage/SDImageCoder.h b/SDWebImage/SDImageCoder.h index efa2352e..ebf151b2 100644 --- a/SDWebImage/SDImageCoder.h +++ b/SDWebImage/SDImageCoder.h @@ -22,7 +22,7 @@ typedef NSDictionary SDImageCoderOptions; FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderDecodeFirstFrameOnly; /** A CGFloat value which is greater than or equal to 1.0. This value specify the image scale factor for decoding. If not provide, use 1.0. (NSNumber) - @note works for `SDImageCoder`, `SDProgressiveImageCoder`, `SDWebImageAnimatedCoder`. + @note works for `SDImageCoder`, `SDProgressiveImageCoder`, `SDAnimatedImageCoder`. */ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderDecodeScaleFactor; @@ -129,7 +129,7 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeCompressio /** Incremental decode the current image data to image. - @note Due to the performance issue for progressive decoding and the integration for image view. This method may only return the first frame image even if the image data is animated image. If you want progressive animated image decoding, conform to `SDWebImageAnimatedCoder` protocol as well and use `animatedImageFrameAtIndex:` instead. + @note Due to the performance issue for progressive decoding and the integration for image view. This method may only return the first frame image even if the image data is animated image. If you want progressive animated image decoding, conform to `SDAnimatedImageCoder` protocol as well and use `animatedImageFrameAtIndex:` instead. @param options A dictionary containing any progressive decoding options. Pass @{SDImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for progressive image @return The decoded image from current data @@ -140,7 +140,7 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeCompressio #pragma mark - Animated Image Provider /** - This is the animated image protocol to provide the basic function for animated image rendering. It's adopted by `SDAnimatedImage` and `SDWebImageAnimatedCoder` + This is the animated image protocol to provide the basic function for animated image rendering. It's adopted by `SDAnimatedImage` and `SDAnimatedImageCoder` */ @protocol SDAnimatedImageProvider diff --git a/SDWebImage/SDWebImageCodersManager.h b/SDWebImage/SDImageCodersManager.h similarity index 93% rename from SDWebImage/SDWebImageCodersManager.h rename to SDWebImage/SDImageCodersManager.h index ef68bd75..0e3b20db 100644 --- a/SDWebImage/SDWebImageCodersManager.h +++ b/SDWebImage/SDImageCodersManager.h @@ -29,12 +29,12 @@ Those methods are called on each coder in the array (using the priority order) until one of them returns YES. That means that coder can decode that data / encode to that format */ -@interface SDWebImageCodersManager : NSObject +@interface SDImageCodersManager : NSObject /** Returns the global shared coders manager instance. */ -@property (nonatomic, class, readonly, nonnull) SDWebImageCodersManager *sharedManager; +@property (nonatomic, class, readonly, nonnull) SDImageCodersManager *sharedManager; /** All coders in coders manager. The coders array is a priority queue, which means the later added coder will have the highest priority diff --git a/SDWebImage/SDWebImageCodersManager.m b/SDWebImage/SDImageCodersManager.m similarity index 89% rename from SDWebImage/SDWebImageCodersManager.m rename to SDWebImage/SDImageCodersManager.m index add2bbae..c1378d1d 100644 --- a/SDWebImage/SDWebImageCodersManager.m +++ b/SDWebImage/SDImageCodersManager.m @@ -6,12 +6,12 @@ * file that was distributed with this source code. */ -#import "SDWebImageCodersManager.h" -#import "SDWebImageImageIOCoder.h" -#import "SDWebImageGIFCoder.h" -#import "SDWebImageAPNGCoder.h" +#import "SDImageCodersManager.h" +#import "SDImageIOCoder.h" +#import "SDImageGIFCoder.h" +#import "SDImageAPNGCoder.h" #ifdef SD_WEBP -#import "SDWebImageWebPCoder.h" +#import "SDImageWebPCoder.h" #endif #import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" @@ -20,13 +20,13 @@ #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); #define UNLOCK(lock) dispatch_semaphore_signal(lock); -@interface SDWebImageCodersManager () +@interface SDImageCodersManager () @property (nonatomic, strong, nonnull) dispatch_semaphore_t codersLock; @end -@implementation SDWebImageCodersManager +@implementation SDImageCodersManager + (nonnull instancetype)sharedManager { static dispatch_once_t once; @@ -40,9 +40,9 @@ - (instancetype)init { if (self = [super init]) { // initialize with default coders - NSMutableArray> *mutableCoders = [@[[SDWebImageImageIOCoder sharedCoder], [SDWebImageGIFCoder sharedCoder], [SDWebImageAPNGCoder sharedCoder]] mutableCopy]; + NSMutableArray> *mutableCoders = [@[[SDImageIOCoder sharedCoder], [SDImageGIFCoder sharedCoder], [SDImageAPNGCoder sharedCoder]] mutableCopy]; #ifdef SD_WEBP - [mutableCoders addObject:[SDWebImageWebPCoder sharedCoder]]; + [mutableCoders addObject:[SDImageWebPCoder sharedCoder]]; #endif _coders = [mutableCoders copy]; _codersLock = dispatch_semaphore_create(1); diff --git a/SDWebImage/SDWebImageGIFCoder.h b/SDWebImage/SDImageGIFCoder.h similarity index 62% rename from SDWebImage/SDWebImageGIFCoder.h rename to SDWebImage/SDImageGIFCoder.h index 6b9c7ec2..3c66fe36 100644 --- a/SDWebImage/SDWebImageGIFCoder.h +++ b/SDWebImage/SDImageGIFCoder.h @@ -12,11 +12,11 @@ /** Built in coder using ImageIO that supports GIF encoding/decoding @note `SDWebImageIOCoder` supports GIF but only as static (will use the 1st frame). - @note Use `SDWebImageGIFCoder` for fully animated GIFs. For `UIImageView`, it will produce animated `UIImage`(`NSImage` on macOS) for rendering. For `SDAnimatedImageView`, it will use `SDAnimatedImage` for rendering. + @note Use `SDImageGIFCoder` for fully animated GIFs. For `UIImageView`, it will produce animated `UIImage`(`NSImage` on macOS) for rendering. For `SDAnimatedImageView`, it will use `SDAnimatedImage` for rendering. @note The recommended approach for animated GIFs is using `SDAnimatedImage` with `SDAnimatedImageView`. It's more performant than `UIImageView` for GIF displaying(especially on memory usage) */ -@interface SDWebImageGIFCoder : NSObject +@interface SDImageGIFCoder : NSObject -@property (nonatomic, class, readonly, nonnull) SDWebImageGIFCoder *sharedCoder; +@property (nonatomic, class, readonly, nonnull) SDImageGIFCoder *sharedCoder; @end diff --git a/SDWebImage/SDWebImageGIFCoder.m b/SDWebImage/SDImageGIFCoder.m similarity index 98% rename from SDWebImage/SDWebImageGIFCoder.m rename to SDWebImage/SDImageGIFCoder.m index efffaffd..4a3a0a6f 100644 --- a/SDWebImage/SDWebImageGIFCoder.m +++ b/SDWebImage/SDImageGIFCoder.m @@ -6,7 +6,7 @@ * file that was distributed with this source code. */ -#import "SDWebImageGIFCoder.h" +#import "SDImageGIFCoder.h" #import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" #import @@ -24,7 +24,7 @@ @implementation SDGIFCoderFrame @end -@implementation SDWebImageGIFCoder { +@implementation SDImageGIFCoder { size_t _width, _height; CGImageSourceRef _imageSource; NSData *_imageData; @@ -56,10 +56,10 @@ } + (instancetype)sharedCoder { - static SDWebImageGIFCoder *coder; + static SDImageGIFCoder *coder; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - coder = [[SDWebImageGIFCoder alloc] init]; + coder = [[SDImageGIFCoder alloc] init]; }); return coder; } @@ -316,7 +316,7 @@ return [imageData copy]; } -#pragma mark - SDWebImageAnimatedCoder +#pragma mark - SDAnimatedImageCoder - (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data options:(nullable SDImageCoderOptions *)options { if (!data) { return nil; diff --git a/SDWebImage/SDWebImageImageIOCoder.h b/SDWebImage/SDImageIOCoder.h similarity index 85% rename from SDWebImage/SDWebImageImageIOCoder.h rename to SDWebImage/SDImageIOCoder.h index 9551a696..634eb7bb 100644 --- a/SDWebImage/SDWebImageImageIOCoder.h +++ b/SDWebImage/SDImageIOCoder.h @@ -14,7 +14,7 @@ GIF Also supports static GIF (meaning will only handle the 1st frame). - For a full GIF support, we recommend `FLAnimatedImage` or our less performant `SDWebImageGIFCoder` + For a full GIF support, we recommend `FLAnimatedImage` or our less performant `SDImageGIFCoder` HEIC This coder also supports HEIC format because ImageIO supports it natively. But it depends on the system capabilities, so it won't work on all devices, see: https://devstreaming-cdn.apple.com/videos/wwdc/2017/511tj33587vdhds/511/511_working_with_heif_and_hevc.pdf @@ -23,8 +23,8 @@ Encode(Software): macOS 10.13 Encode(Hardware): !Simulator && ((iOS 11 && A10FusionChip) || (macOS 10.13 && 6thGenerationIntelCPU)) */ -@interface SDWebImageImageIOCoder : NSObject +@interface SDImageIOCoder : NSObject -@property (nonatomic, class, readonly, nonnull) SDWebImageImageIOCoder *sharedCoder; +@property (nonatomic, class, readonly, nonnull) SDImageIOCoder *sharedCoder; @end diff --git a/SDWebImage/SDWebImageImageIOCoder.m b/SDWebImage/SDImageIOCoder.m similarity index 98% rename from SDWebImage/SDWebImageImageIOCoder.m rename to SDWebImage/SDImageIOCoder.m index 071d6801..e24c20f4 100644 --- a/SDWebImage/SDWebImageImageIOCoder.m +++ b/SDWebImage/SDImageIOCoder.m @@ -6,13 +6,13 @@ * file that was distributed with this source code. */ -#import "SDWebImageImageIOCoder.h" +#import "SDImageIOCoder.h" #import "SDWebImageCoderHelper.h" #import "NSImage+Compatibility.h" #import #import "NSData+ImageContentType.h" -@implementation SDWebImageImageIOCoder { +@implementation SDImageIOCoder { size_t _width, _height; CGImagePropertyOrientation _orientation; CGImageSourceRef _imageSource; @@ -38,10 +38,10 @@ } + (instancetype)sharedCoder { - static SDWebImageImageIOCoder *coder; + static SDImageIOCoder *coder; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - coder = [[SDWebImageImageIOCoder alloc] init]; + coder = [[SDImageIOCoder alloc] init]; }); return coder; } diff --git a/SDWebImage/SDWebImageLoader.m b/SDWebImage/SDWebImageLoader.m index dd55b65e..1628302a 100644 --- a/SDWebImage/SDWebImageLoader.m +++ b/SDWebImage/SDWebImageLoader.m @@ -8,7 +8,7 @@ #import "SDWebImageLoader.h" #import "SDWebImageCacheKeyFilter.h" -#import "SDWebImageCodersManager.h" +#import "SDImageCodersManager.h" #import "SDWebImageCoderHelper.h" #import "SDAnimatedImage.h" #import "UIImage+WebCache.h" @@ -47,7 +47,7 @@ UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, } } if (!image) { - image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}]; + image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}]; } if (image) { BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; @@ -94,7 +94,7 @@ UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull id progressiveCoder = objc_getAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey); if (!progressiveCoder) { // We need to create a new instance for progressive decoding to avoid conflicts - for (idcoder in [SDWebImageCodersManager sharedManager].coders.reverseObjectEnumerator) { + for (idcoder in [SDImageCodersManager sharedManager].coders.reverseObjectEnumerator) { if ([coder conformsToProtocol:@protocol(SDProgressiveImageCoder)] && [((id)coder) canIncrementalDecodeFromData:imageData]) { progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:@{SDImageCoderDecodeScaleFactor : @(scale)}]; diff --git a/SDWebImage/UIImage+GIF.m b/SDWebImage/UIImage+GIF.m index 512baa21..d2672721 100644 --- a/SDWebImage/UIImage+GIF.m +++ b/SDWebImage/UIImage+GIF.m @@ -8,7 +8,7 @@ */ #import "UIImage+GIF.h" -#import "SDWebImageGIFCoder.h" +#import "SDImageGIFCoder.h" @implementation UIImage (GIF) @@ -21,7 +21,7 @@ return nil; } SDImageCoderOptions *options = @{SDImageCoderDecodeFirstFrameOnly : @(firstFrameOnly)}; - return [[SDWebImageGIFCoder sharedCoder] decodedImageWithData:data options:options]; + return [[SDImageGIFCoder sharedCoder] decodedImageWithData:data options:options]; } @end diff --git a/SDWebImage/UIImage+MultiFormat.m b/SDWebImage/UIImage+MultiFormat.m index 2fc7e9f7..0e59b18d 100644 --- a/SDWebImage/UIImage+MultiFormat.m +++ b/SDWebImage/UIImage+MultiFormat.m @@ -7,7 +7,7 @@ */ #import "UIImage+MultiFormat.h" -#import "SDWebImageCodersManager.h" +#import "SDImageCodersManager.h" @implementation UIImage (MultiFormat) @@ -23,7 +23,7 @@ scale = 1; } SDImageCoderOptions *options = @{SDImageCoderDecodeScaleFactor : @(scale)}; - return [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:options]; + return [[SDImageCodersManager sharedManager] decodedImageWithData:data options:options]; } - (nullable NSData *)sd_imageData { @@ -36,7 +36,7 @@ - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat compressionQuality:(double)compressionQuality { SDImageCoderOptions *options = @{SDImageCoderEncodeCompressionQuality : @(compressionQuality)}; - return [[SDWebImageCodersManager sharedManager] encodedDataWithImage:self format:imageFormat options:options]; + return [[SDImageCodersManager sharedManager] encodedDataWithImage:self format:imageFormat options:options]; } @end diff --git a/SDWebImage/WebP/SDWebImageWebPCoder.h b/SDWebImage/WebP/SDImageWebPCoder.h similarity index 68% rename from SDWebImage/WebP/SDWebImageWebPCoder.h rename to SDWebImage/WebP/SDImageWebPCoder.h index 461a6840..ae62a6b8 100644 --- a/SDWebImage/WebP/SDWebImageWebPCoder.h +++ b/SDWebImage/WebP/SDImageWebPCoder.h @@ -14,9 +14,9 @@ /** Built in coder that supports WebP and animated WebP */ -@interface SDWebImageWebPCoder : NSObject +@interface SDImageWebPCoder : NSObject -@property (nonatomic, class, readonly, nonnull) SDWebImageWebPCoder *sharedCoder; +@property (nonatomic, class, readonly, nonnull) SDImageWebPCoder *sharedCoder; @end diff --git a/SDWebImage/WebP/SDWebImageWebPCoder.m b/SDWebImage/WebP/SDImageWebPCoder.m similarity index 99% rename from SDWebImage/WebP/SDWebImageWebPCoder.m rename to SDWebImage/WebP/SDImageWebPCoder.m index 6a998b02..7686003f 100644 --- a/SDWebImage/WebP/SDWebImageWebPCoder.m +++ b/SDWebImage/WebP/SDImageWebPCoder.m @@ -8,7 +8,7 @@ #ifdef SD_WEBP -#import "SDWebImageWebPCoder.h" +#import "SDImageWebPCoder.h" #import "SDWebImageCoderHelper.h" #import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" @@ -48,7 +48,7 @@ dispatch_semaphore_signal(self->_lock); @implementation SDWebPCoderFrame @end -@implementation SDWebImageWebPCoder { +@implementation SDImageWebPCoder { WebPIDecoder *_idec; WebPDemuxer *_demux; NSData *_imageData; @@ -82,10 +82,10 @@ dispatch_semaphore_signal(self->_lock); } + (instancetype)sharedCoder { - static SDWebImageWebPCoder *coder; + static SDImageWebPCoder *coder; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - coder = [[SDWebImageWebPCoder alloc] init]; + coder = [[SDImageWebPCoder alloc] init]; }); return coder; } @@ -525,7 +525,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { free((void *)data); } -#pragma mark - SDWebImageAnimatedCoder +#pragma mark - SDAnimatedImageCoder - (instancetype)initWithAnimatedImageData:(NSData *)data options:(nullable SDImageCoderOptions *)options { if (!data) { return nil; diff --git a/SDWebImage/WebP/UIImage+WebP.m b/SDWebImage/WebP/UIImage+WebP.m index 919af914..9fe69554 100644 --- a/SDWebImage/WebP/UIImage+WebP.m +++ b/SDWebImage/WebP/UIImage+WebP.m @@ -9,7 +9,7 @@ #ifdef SD_WEBP #import "UIImage+WebP.h" -#import "SDWebImageWebPCoder.h" +#import "SDImageWebPCoder.h" @implementation UIImage (WebP) @@ -22,7 +22,7 @@ return nil; } SDImageCoderOptions *options = @{SDImageCoderDecodeFirstFrameOnly : @(firstFrameOnly)}; - return [[SDWebImageWebPCoder sharedCoder] decodedImageWithData:data options:options]; + return [[SDImageWebPCoder sharedCoder] decodedImageWithData:data options:options]; } @end diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index c383d2c8..ad7445d9 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -52,11 +52,11 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import -#import +#import #import -#import -#import -#import +#import +#import +#import #import #import #import @@ -90,5 +90,5 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; // WebP #if __has_include() #import -#import +#import #endif From 0423cc2cf0ec952c0a9ea0720fd5a6c40b0a4dd4 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 26 Apr 2018 22:59:04 +0800 Subject: [PATCH 175/361] Update the test for image coder renaming --- SDWebImage/SDImageGIFCoder.h | 4 +-- .../project.pbxproj | 28 +++++++++---------- Tests/Tests/SDAnimatedImageTest.m | 4 +-- Tests/Tests/SDImageCacheTests.m | 8 +++--- ...mageDecoderTests.m => SDImageCoderTests.m} | 10 +++---- Tests/Tests/SDWebImageDownloaderTests.m | 8 +++--- ...ageTestDecoder.h => SDWebImageTestCoder.h} | 4 +-- ...ageTestDecoder.m => SDWebImageTestCoder.m} | 12 ++++---- 8 files changed, 39 insertions(+), 39 deletions(-) rename Tests/Tests/{SDWebImageDecoderTests.m => SDImageCoderTests.m} (96%) rename Tests/Tests/{SDWebImageTestDecoder.h => SDWebImageTestCoder.h} (72%) rename Tests/Tests/{SDWebImageTestDecoder.m => SDWebImageTestCoder.m} (79%) diff --git a/SDWebImage/SDImageGIFCoder.h b/SDWebImage/SDImageGIFCoder.h index 3c66fe36..1ecc7cb5 100644 --- a/SDWebImage/SDImageGIFCoder.h +++ b/SDWebImage/SDImageGIFCoder.h @@ -10,8 +10,8 @@ #import "SDImageCoder.h" /** - Built in coder using ImageIO that supports GIF encoding/decoding - @note `SDWebImageIOCoder` supports GIF but only as static (will use the 1st frame). + Built in coder using ImageIO that supports animated GIF encoding/decoding + @note `SDImageIOCoder` supports GIF but only as static (will use the 1st frame). @note Use `SDImageGIFCoder` for fully animated GIFs. For `UIImageView`, it will produce animated `UIImage`(`NSImage` on macOS) for rendering. For `SDAnimatedImageView`, it will use `SDAnimatedImage` for rendering. @note The recommended approach for animated GIFs is using `SDAnimatedImage` with `SDAnimatedImageView`. It's more performant than `UIImageView` for GIF displaying(especially on memory usage) */ diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 63e363f3..cd6a0871 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -29,7 +29,7 @@ 32B99E8B203AF8690017FD66 /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */; }; 32B99E9B203B2EDD0017FD66 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; }; 32B99E9C203B2EE40017FD66 /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */; }; - 32B99E9D203B2F7D0017FD66 /* SDWebImageTestDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */; }; + 32B99E9D203B2F7D0017FD66 /* SDWebImageTestCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32E6F0311F3A1B4700A945E6 /* SDWebImageTestCoder.m */; }; 32B99E9E203B2F810017FD66 /* SDMockFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */; }; 32B99EA2203B31360017FD66 /* MonochromeTestImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */; }; 32B99EA3203B31360017FD66 /* TestImage.gif in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB61D7EF8200086B6E9 /* TestImage.gif */; }; @@ -38,15 +38,15 @@ 32B99EA6203B31360017FD66 /* TestImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB81D7EF8260086B6E9 /* TestImage.png */; }; 32B99EA7203B31360017FD66 /* TestImageAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */; }; 32B99EA8203B31360017FD66 /* TestImageStatic.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259EB1F39E3240096FE0E /* TestImageStatic.webp */; }; - 32B99EA9203B34B60017FD66 /* SDWebImageDecoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */; }; + 32B99EA9203B34B60017FD66 /* SDImageCoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDImageCoderTests.m */; }; 32B99EAA203B365F0017FD66 /* SDImageCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA248D68195475D800390AB0 /* SDImageCacheTests.m */; }; 32B99EAB203B36620017FD66 /* SDWebImageManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA248D6A195476AC00390AB0 /* SDWebImageManagerTests.m */; }; 32B99EAC203B36650017FD66 /* SDWebImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */; }; 32B99EAD203B36690017FD66 /* SDWebImagePrefetcherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */; }; 32B99EAE203B366C0017FD66 /* SDWebCacheCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */; }; - 32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */; }; + 32E6F0321F3A1B4700A945E6 /* SDWebImageTestCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32E6F0311F3A1B4700A945E6 /* SDWebImageTestCoder.m */; }; 37D122881EC48B5E00D98CEB /* SDMockFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */; }; - 433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */; }; + 433BBBB51D7EF5C00086B6E9 /* SDImageCoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDImageCoderTests.m */; }; 433BBBB71D7EF8200086B6E9 /* TestImage.gif in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB61D7EF8200086B6E9 /* TestImage.gif */; }; 433BBBB91D7EF8260086B6E9 /* TestImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB81D7EF8260086B6E9 /* TestImage.png */; }; 433BBBBB1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */; }; @@ -84,12 +84,12 @@ 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDCategoriesTests.m; sourceTree = ""; }; 32B99E92203B2DF90017FD66 /* Tests Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 32B99E96203B2DF90017FD66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 32E6F0301F3A1B4700A945E6 /* SDWebImageTestDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestDecoder.h; sourceTree = ""; }; - 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestDecoder.m; sourceTree = ""; }; + 32E6F0301F3A1B4700A945E6 /* SDWebImageTestCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestCoder.h; sourceTree = ""; }; + 32E6F0311F3A1B4700A945E6 /* SDWebImageTestCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestCoder.m; sourceTree = ""; }; 37D122861EC48B5E00D98CEB /* SDMockFileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDMockFileManager.h; sourceTree = ""; }; 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDMockFileManager.m; sourceTree = ""; }; 3B82F4E5C79656CB9C5667F6 /* Pods-Tests Mac.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests Mac.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests Mac/Pods-Tests Mac.debug.xcconfig"; sourceTree = ""; }; - 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDecoderTests.m; sourceTree = ""; }; + 433BBBB41D7EF5C00086B6E9 /* SDImageCoderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageCoderTests.m; sourceTree = ""; }; 433BBBB61D7EF8200086B6E9 /* TestImage.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = TestImage.gif; sourceTree = ""; }; 433BBBB81D7EF8260086B6E9 /* TestImage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TestImage.png; sourceTree = ""; }; 433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = MonochromeTestImage.jpg; sourceTree = ""; }; @@ -209,7 +209,7 @@ DA248D68195475D800390AB0 /* SDImageCacheTests.m */, DA248D6A195476AC00390AB0 /* SDWebImageManagerTests.m */, 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */, - 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */, + 433BBBB41D7EF5C00086B6E9 /* SDImageCoderTests.m */, 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */, 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */, 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */, @@ -223,8 +223,8 @@ 328BB6DC20825E9800760D6C /* SDWebImageTestCache.m */, 3226ECB920754F7700FAFACF /* SDWebImageTestDownloadOperation.h */, 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */, - 32E6F0301F3A1B4700A945E6 /* SDWebImageTestDecoder.h */, - 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */, + 32E6F0301F3A1B4700A945E6 /* SDWebImageTestCoder.h */, + 32E6F0311F3A1B4700A945E6 /* SDWebImageTestCoder.m */, 3264FF2D205D42CB00F6BD48 /* SDWebImageTestTransformer.h */, 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */, 323B8E1D20862322008952BE /* SDWebImageTestLoader.h */, @@ -484,10 +484,10 @@ 32B99EAA203B365F0017FD66 /* SDImageCacheTests.m in Sources */, 32B99EAD203B36690017FD66 /* SDWebImagePrefetcherTests.m in Sources */, 32B99EAE203B366C0017FD66 /* SDWebCacheCategoriesTests.m in Sources */, - 32B99E9D203B2F7D0017FD66 /* SDWebImageTestDecoder.m in Sources */, + 32B99E9D203B2F7D0017FD66 /* SDWebImageTestCoder.m in Sources */, 32B99E9E203B2F810017FD66 /* SDMockFileManager.m in Sources */, 32B99EAB203B36620017FD66 /* SDWebImageManagerTests.m in Sources */, - 32B99EA9203B34B60017FD66 /* SDWebImageDecoderTests.m in Sources */, + 32B99EA9203B34B60017FD66 /* SDImageCoderTests.m in Sources */, 3264FF30205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */, 320630412085A37C006E0FA4 /* SDAnimatedImageTest.m in Sources */, 32B99E9B203B2EDD0017FD66 /* SDTestCase.m in Sources */, @@ -500,7 +500,7 @@ buildActionMask = 2147483647; files = ( 323B8E1F20862322008952BE /* SDWebImageTestLoader.m in Sources */, - 32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */, + 32E6F0321F3A1B4700A945E6 /* SDWebImageTestCoder.m in Sources */, 3226ECBB20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */, 3254C32020641077008D1022 /* SDWebImageTransformerTests.m in Sources */, 32A571562037DB2D002EDAAE /* SDAnimatedImageTest.m in Sources */, @@ -514,7 +514,7 @@ DA248D6B195476AC00390AB0 /* SDWebImageManagerTests.m in Sources */, 32B99E8B203AF8690017FD66 /* SDCategoriesTests.m in Sources */, 3264FF2F205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */, - 433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */, + 433BBBB51D7EF5C00086B6E9 /* SDImageCoderTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index 7c6907a0..92ef3f2c 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -62,7 +62,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun - (void)test03AnimatedImageInitWithAnimatedCoder { NSData *validData = [self testGIFData]; - SDWebImageGIFCoder *coder = [[SDWebImageGIFCoder alloc] initWithAnimatedImageData:validData options:nil]; + SDImageGIFCoder *coder = [[SDImageGIFCoder alloc] initWithAnimatedImageData:validData options:nil]; SDAnimatedImage *image = [[SDAnimatedImage alloc] initWithAnimatedCoder:coder scale:1]; expect(image).notTo.beNil(); // enough, other can be test with InitWithData @@ -154,7 +154,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun - (void)test09AnimatedImageViewSetProgressiveAnimatedImage { NSData *gifData = [self testGIFData]; - SDWebImageGIFCoder *progressiveCoder = [[SDWebImageGIFCoder alloc] initIncrementalWithOptions:nil]; + SDImageGIFCoder *progressiveCoder = [[SDImageGIFCoder alloc] initIncrementalWithOptions:nil]; // simulate progressive decode, pass partial data NSData *partialData = [gifData subdataWithRange:NSMakeRange(0, gifData.length - 1)]; [progressiveCoder updateIncrementalData:partialData finished:NO]; diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index f884cfeb..ce14a950 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -7,7 +7,7 @@ */ #import "SDTestCase.h" -#import "SDWebImageTestDecoder.h" +#import "SDWebImageTestCoder.h" #import "SDMockFileManager.h" #import "SDWebImageTestCache.h" @@ -275,8 +275,8 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; - (void)test41ThatCustomDecoderWorksForImageCache { XCTestExpectation *expectation = [self expectationWithDescription:@"Custom decoder for SDImageCache not works"]; SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"TestDecode"]; - SDWebImageTestDecoder *testDecoder = [[SDWebImageTestDecoder alloc] init]; - [[SDWebImageCodersManager sharedManager] addCoder:testDecoder]; + SDWebImageTestCoder *testDecoder = [[SDWebImageTestCoder alloc] init]; + [[SDImageCodersManager sharedManager] addCoder:testDecoder]; NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"png"]; UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; NSString *key = @"TestPNGImageEncodedToDataAndRetrieveToJPEG"; @@ -310,7 +310,7 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; XCTFail(@"Custom decoder not work for SDImageCache, check -[SDWebImageTestDecoder decodedImageWithData:]"); } - [[SDWebImageCodersManager sharedManager] removeCoder:testDecoder]; + [[SDImageCodersManager sharedManager] removeCoder:testDecoder]; [[SDImageCache sharedImageCache] removeImageForKey:key withCompletion:^{ [expectation fulfill]; diff --git a/Tests/Tests/SDWebImageDecoderTests.m b/Tests/Tests/SDImageCoderTests.m similarity index 96% rename from Tests/Tests/SDWebImageDecoderTests.m rename to Tests/Tests/SDImageCoderTests.m index 077e2b30..ea2907d9 100644 --- a/Tests/Tests/SDWebImageDecoderTests.m +++ b/Tests/Tests/SDImageCoderTests.m @@ -81,33 +81,33 @@ - (void)test09ThatStaticWebPCoderWorks { NSURL *staticWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageStatic" withExtension:@"webp"]; - [self verifyCoder:[SDWebImageWebPCoder sharedCoder] + [self verifyCoder:[SDImageWebPCoder sharedCoder] withLocalImageURL:staticWebPURL isAnimatedImage:NO]; } - (void)test10ThatAnimatedWebPCoderWorks { NSURL *animatedWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageAnimated" withExtension:@"webp"]; - [self verifyCoder:[SDWebImageWebPCoder sharedCoder] + [self verifyCoder:[SDImageWebPCoder sharedCoder] withLocalImageURL:animatedWebPURL isAnimatedImage:YES]; } - (void)test11ThatAPNGPCoderWorks { NSURL *animatedWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageAnimated" withExtension:@"apng"]; - [self verifyCoder:[SDWebImageAPNGCoder sharedCoder] + [self verifyCoder:[SDImageAPNGCoder sharedCoder] withLocalImageURL:animatedWebPURL isAnimatedImage:YES]; } - (void)test20ThatOurGIFCoderWorksNotFLAnimatedImage { NSURL *gifURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImage" withExtension:@"gif"]; - [self verifyCoder:[SDWebImageGIFCoder sharedCoder] + [self verifyCoder:[SDImageGIFCoder sharedCoder] withLocalImageURL:gifURL isAnimatedImage:YES]; } -- (void)verifyCoder:(id)coder +- (void)verifyCoder:(id)coder withLocalImageURL:(NSURL *)imageUrl isAnimatedImage:(BOOL)isAnimated { NSData *inputImageData = [NSData dataWithContentsOfURL:imageUrl]; diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index e83b93da..93e995ba 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -9,7 +9,7 @@ #import "SDTestCase.h" #import "SDWebImageTestDownloadOperation.h" -#import "SDWebImageTestDecoder.h" +#import "SDWebImageTestCoder.h" #import "SDWebImageTestLoader.h" /** @@ -346,8 +346,8 @@ - (void)test22ThatCustomDecoderWorksForImageDownload { XCTestExpectation *expectation = [self expectationWithDescription:@"Custom decoder for SDWebImageDownloader not works"]; SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] init]; - SDWebImageTestDecoder *testDecoder = [[SDWebImageTestDecoder alloc] init]; - [[SDWebImageCodersManager sharedManager] addCoder:testDecoder]; + SDWebImageTestCoder *testDecoder = [[SDWebImageTestCoder alloc] init]; + [[SDImageCodersManager sharedManager] addCoder:testDecoder]; NSURL * testImageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImage" withExtension:@"png"]; // Decoded result is JPEG @@ -360,7 +360,7 @@ if (![data1 isEqualToData:data2]) { XCTFail(@"The image data is not equal to cutom decoder, check -[SDWebImageTestDecoder decodedImageWithData:]"); } - [[SDWebImageCodersManager sharedManager] removeCoder:testDecoder]; + [[SDImageCodersManager sharedManager] removeCoder:testDecoder]; [expectation fulfill]; }]; diff --git a/Tests/Tests/SDWebImageTestDecoder.h b/Tests/Tests/SDWebImageTestCoder.h similarity index 72% rename from Tests/Tests/SDWebImageTestDecoder.h rename to Tests/Tests/SDWebImageTestCoder.h index eefb743f..d822b1e2 100644 --- a/Tests/Tests/SDWebImageTestDecoder.h +++ b/Tests/Tests/SDWebImageTestCoder.h @@ -8,8 +8,8 @@ */ #import -#import +#import -@interface SDWebImageTestDecoder : NSObject +@interface SDWebImageTestCoder : NSObject @end diff --git a/Tests/Tests/SDWebImageTestDecoder.m b/Tests/Tests/SDWebImageTestCoder.m similarity index 79% rename from Tests/Tests/SDWebImageTestDecoder.m rename to Tests/Tests/SDWebImageTestCoder.m index feda04ae..cfe7490f 100644 --- a/Tests/Tests/SDWebImageTestDecoder.m +++ b/Tests/Tests/SDWebImageTestCoder.m @@ -7,9 +7,9 @@ * file that was distributed with this source code. */ -#import "SDWebImageTestDecoder.h" +#import "SDWebImageTestCoder.h" -@implementation SDWebImageTestDecoder +@implementation SDWebImageTestCoder - (BOOL)canDecodeFromData:(nullable NSData *)data { return YES; @@ -19,13 +19,13 @@ return YES; } -- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options { +- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderOptions *)options { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"jpg"]; UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; return image; } -- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options +- (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)options { self = [super init]; if (self) { @@ -37,7 +37,7 @@ return; } -- (UIImage *)incrementalDecodedImageWithOptions:(SDWebImageCoderOptions *)options { +- (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options { NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"gif"]; UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath]; return image; @@ -47,7 +47,7 @@ return YES; } -- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDWebImageCoderOptions *)options { +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDImageCoderOptions *)options { NSString *testString = @"TestEncode"; NSData *data = [testString dataUsingEncoding:NSUTF8StringEncoding]; return data; From 9bf79ab85b26a70dd7ad5b63ff0a8925dfad82ad Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 2 May 2018 20:30:34 +0800 Subject: [PATCH 176/361] Fix WebP Encoding only works for RGBA8888 CGImage but not other color mode. Detect the current CGImage color mode, covert the all other case to RGB888/RGBA8888 using vImage --- SDWebImage/WebP/SDImageWebPCoder.m | 101 +++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 6 deletions(-) diff --git a/SDWebImage/WebP/SDImageWebPCoder.m b/SDWebImage/WebP/SDImageWebPCoder.m index 59510b34..6de0b5ec 100644 --- a/SDWebImage/WebP/SDImageWebPCoder.m +++ b/SDWebImage/WebP/SDImageWebPCoder.m @@ -24,6 +24,7 @@ #import "webp/demux.h" #import "webp/mux.h" #endif +#import #define LOCK(...) dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER); \ __VA_ARGS__; \ @@ -210,7 +211,7 @@ dispatch_semaphore_signal(self->_lock); - (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)options { self = [super init]; if (self) { - // Progressive images need transparent, so always use premultiplied RGBA + // Progressive images need transparent, so always use premultiplied BGRA _idec = WebPINewRGB(MODE_bgrA, NULL, 0, 0); CGFloat scale = 1; if ([options valueForKey:SDImageCoderDecodeScaleFactor]) { @@ -497,18 +498,106 @@ dispatch_semaphore_signal(self->_lock); } size_t bytesPerRow = CGImageGetBytesPerRow(imageRef); + CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); + CGImageAlphaInfo alphaInfo = bitmapInfo & kCGBitmapAlphaInfoMask; + CGBitmapInfo byteOrderInfo = bitmapInfo & kCGBitmapByteOrderMask; + BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone || + alphaInfo == kCGImageAlphaNoneSkipFirst || + alphaInfo == kCGImageAlphaNoneSkipLast); + BOOL byteOrderNormal = NO; + switch (byteOrderInfo) { + case kCGBitmapByteOrderDefault: { + byteOrderNormal = YES; + } break; + case kCGBitmapByteOrder32Little: { + } break; + case kCGBitmapByteOrder32Big: { + byteOrderNormal = YES; + } break; + default: break; + } + // If we can not get bitmap buffer, early return CGDataProviderRef dataProvider = CGImageGetDataProvider(imageRef); if (!dataProvider) { return nil; } CFDataRef dataRef = CGDataProviderCopyData(dataProvider); - uint8_t *rgba = (uint8_t *)CFDataGetBytePtr(dataRef); + if (!dataRef) { + return nil; + } - uint8_t *data = NULL; + uint8_t *rgba = NULL; + // We could not assume that input CGImage's color mode is always RGB888/RGBA8888. Convert all other cases to target color mode using vImage + if (byteOrderNormal && ((alphaInfo == kCGImageAlphaNone) || (alphaInfo == kCGImageAlphaLast))) { + // If the input CGImage is already RGB888/RGBA8888 + rgba = (uint8_t *)CFDataGetBytePtr(dataRef); + } else { + // Convert all other cases to target color mode using vImage + vImageConverterRef convertor = NULL; + vImage_Error error = kvImageNoError; + + vImage_CGImageFormat srcFormat = { + .bitsPerComponent = (uint32_t)CGImageGetBitsPerComponent(imageRef), + .bitsPerPixel = (uint32_t)CGImageGetBitsPerPixel(imageRef), + .colorSpace = CGImageGetColorSpace(imageRef), + .bitmapInfo = bitmapInfo + }; + vImage_CGImageFormat destFormat = { + .bitsPerComponent = 8, + .bitsPerPixel = hasAlpha ? 32 : 24, + .colorSpace = [SDImageCoderHelper colorSpaceGetDeviceRGB], + .bitmapInfo = hasAlpha ? kCGImageAlphaLast | kCGBitmapByteOrderDefault : kCGImageAlphaNone | kCGBitmapByteOrderDefault // RGB888/RGBA8888 (Non-premultiplied to works for libwebp) + }; + + convertor = vImageConverter_CreateWithCGImageFormat(&srcFormat, &destFormat, NULL, kvImageNoFlags, &error); + if (error != kvImageNoError) { + CFRelease(dataRef); + return nil; + } + + vImage_Buffer src = { + .data = (uint8_t *)CFDataGetBytePtr(dataRef), + .width = width, + .height = height, + .rowBytes = bytesPerRow + }; + vImage_Buffer dest; + + error = vImageBuffer_Init(&dest, height, width, destFormat.bitsPerPixel, kvImageNoFlags); + if (error != kvImageNoError) { + CFRelease(dataRef); + return nil; + } + + // Convert input color mode to RGB888/RGBA8888 + error = vImageConvert_AnyToAny(convertor, &src, &dest, NULL, kvImageNoFlags); + if (error != kvImageNoError) { + CFRelease(dataRef); + return nil; + } + + rgba = dest.data; // Converted buffer + bytesPerRow = dest.rowBytes; // Converted bytePerRow + CFRelease(dataRef); + dataRef = NULL; + } + + uint8_t *data = NULL; // Output WebP data float qualityFactor = quality * 100; // WebP quality is 0-100 - size_t size = WebPEncodeRGBA(rgba, (int)width, (int)height, (int)bytesPerRow, qualityFactor, &data); - CFRelease(dataRef); - rgba = NULL; + // Encode RGB888/RGBA8888 buffer to WebP data + size_t size; + if (hasAlpha) { + size = WebPEncodeRGBA(rgba, (int)width, (int)height, (int)bytesPerRow, qualityFactor, &data); + } else { + size = WebPEncodeRGB(rgba, (int)width, (int)height, (int)bytesPerRow, qualityFactor, &data); + } + if (dataRef) { + CFRelease(dataRef); // free non-converted rgba buffer + dataRef = NULL; + } else { + free(rgba); // free converted rgba buffer + rgba = NULL; + } if (size) { // success From d7ceb2764b01f56abb505667aba7796e55436d80 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 3 May 2018 21:00:20 +0800 Subject: [PATCH 177/361] Add options to specify query cache sync/async behavior. This can help for web cache manager to avoid flashing during cell reusing. --- SDWebImage/SDImageCache.h | 23 ++++++++++++++--------- SDWebImage/SDImageCache.m | 22 +++++++++++++++------- SDWebImage/SDWebImageDefine.h | 30 ++++++++++++++++++------------ 3 files changed, 47 insertions(+), 28 deletions(-) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index f2e58128..1bb5b7cd 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -14,36 +14,41 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { /** - * By default, we do not query disk data when the image is cached in memory. This mask can force to query disk data at the same time. + * By default, we do not query image data when the image is already cached in memory. This mask can force to query image data at the same time. However, this query is asynchronously unless you specify `SDImageCacheQueryMemoryDataSync` */ - SDImageCacheQueryDataWhenInMemory = 1 << 0, + SDImageCacheQueryMemoryData = 1 << 0, /** - * By default, we query the memory cache synchronously, disk cache asynchronously. This mask can force to query disk cache synchronously. + * By default, when you only specify `SDImageCacheQueryMemoryData`, we query the memory image data asynchronously. Combined this mask as well to query the memory image data synchronously. */ - SDImageCacheQueryDiskSync = 1 << 1, + SDImageCacheQueryMemoryDataSync = 1 << 1, + /** + * By default, when the memory cache miss, we query the disk cache asynchronously. This mask can force to query disk cache (when memory cache miss) synchronously. + @note These 3 query options can be combined together. For the full list about these masks combination, see wiki page. + */ + SDImageCacheQueryDiskDataSync = 1 << 2, /** * By default, images are decoded respecting their original size. On iOS, this flag will scale down the * images to a size compatible with the constrained memory of devices. */ - SDImageCacheScaleDownLargeImages = 1 << 2, + SDImageCacheScaleDownLargeImages = 1 << 3, /** * We usually don't apply transform on animated images as most transformers could not manage animated images. * Use this flag to transform them anyway. */ - SDImageCacheTransformAnimatedImage = 1 << 3, + SDImageCacheTransformAnimatedImage = 1 << 4, /** * By default, we will decode the image in the background during cache query and download from the network. This can help to improve performance because when rendering image on the screen, it need to be firstly decoded. But this happen on the main queue by Core Animation. * However, this process may increase the memory usage as well. If you are experiencing a issue due to excessive memory consumption, This flag can prevent decode the image. */ - SDImageCacheAvoidDecodeImage = 1 << 4, + SDImageCacheAvoidDecodeImage = 1 << 5, /** * By default, we decode the animated image. This flag can force decode the first frame only and produece the static image. */ - SDImageCacheDecodeFirstFrameOnly = 1 << 5, + SDImageCacheDecodeFirstFrameOnly = 1 << 6, /** * By default, for `SDAnimatedImage`, we decode the animated image frame during rendering to reduce memory usage. This flag actually trigger `preloadAllAnimatedImageFrames = YES` after image load from disk cache */ - SDImageCachePreloadAllFrames = 1 << 6 + SDImageCachePreloadAllFrames = 1 << 7 }; /** diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 9a370943..00744d8e 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -346,7 +346,7 @@ // First check the in-memory cache... UIImage *image = [self imageFromMemoryCacheForKey:key]; - BOOL shouldQueryMemoryOnly = (image && !(options & SDImageCacheQueryDataWhenInMemory)); + BOOL shouldQueryMemoryOnly = (image && !(options & SDImageCacheQueryMemoryData)); if (shouldQueryMemoryOnly) { if (doneBlock) { doneBlock(image, nil, SDImageCacheTypeMemory); @@ -354,7 +354,13 @@ return nil; } + // Second check the disk cache... NSOperation *operation = [NSOperation new]; + // Check whether we need to synchronously query disk + // 1. in-memory cache hit & memoryDataSync + // 2. in-memory cache miss & diskDataSync + BOOL shouldQueryDiskSync = ((image && options & SDImageCacheQueryMemoryDataSync) || + (!image && options & SDImageCacheQueryDiskDataSync)); void(^queryDiskBlock)(void) = ^{ if (operation.isCancelled) { // do not call the completion if cancelled @@ -366,7 +372,7 @@ UIImage *diskImage; SDImageCacheType cacheType = SDImageCacheTypeDisk; if (image) { - // the image is from in-memory cache + // the image is from in-memory cache, but need image data diskImage = image; cacheType = SDImageCacheTypeMemory; } else if (diskData) { @@ -386,7 +392,7 @@ } if (doneBlock) { - if (options & SDImageCacheQueryDiskSync) { + if (shouldQueryDiskSync) { doneBlock(diskImage, diskData, cacheType); } else { dispatch_async(dispatch_get_main_queue(), ^{ @@ -397,8 +403,9 @@ } }; - if (options & SDImageCacheQueryDiskSync) { - queryDiskBlock(); + // Query in ioQueue to keep IO-safe + if (shouldQueryDiskSync) { + dispatch_sync(self.ioQueue, queryDiskBlock); } else { dispatch_async(self.ioQueue, queryDiskBlock); } @@ -578,8 +585,9 @@ - (id)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock { SDImageCacheOptions cacheOptions = 0; - if (options & SDWebImageQueryDataWhenInMemory) cacheOptions |= SDImageCacheQueryDataWhenInMemory; - if (options & SDWebImageQueryDiskSync) cacheOptions |= SDImageCacheQueryDiskSync; + if (options & SDWebImageQueryMemoryData) cacheOptions |= SDImageCacheQueryMemoryData; + if (options & SDWebImageQueryMemoryDataSync) cacheOptions |= SDImageCacheQueryMemoryDataSync; + if (options & SDWebImageQueryDiskDataSync) cacheOptions |= SDImageCacheQueryDiskDataSync; if (options & SDWebImageTransformAnimatedImage) cacheOptions |= SDImageCacheTransformAnimatedImage; if (options & SDWebImageDecodeFirstFrameOnly) cacheOptions |= SDImageCacheDecodeFirstFrameOnly; if (options & SDWebImagePreloadAllFrames) cacheOptions |= SDImageCachePreloadAllFrames; diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index 7236a6a8..6aa0e326 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -133,48 +133,54 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { SDWebImageScaleDownLargeImages = 1 << 12, /** - * By default, we do not query disk data when the image is cached in memory. This mask can force to query disk data at the same time. - * This flag is recommend to be used with `SDWebImageQueryDiskSync` to ensure the image is loaded in the same runloop. + * By default, we do not query image data when the image is already cached in memory. This mask can force to query image data at the same time. However, this query is asynchronously unless you specify `SDWebImageQueryMemoryDataSync` */ - SDWebImageQueryDataWhenInMemory = 1 << 13, + SDWebImageQueryMemoryData = 1 << 13, /** - * By default, we query the memory cache synchronously, disk cache asynchronously. This mask can force to query disk cache synchronously to ensure that image is loaded in the same runloop. - * This flag can avoid flashing during cell reuse if you disable memory cache or in some other cases. + * By default, when you only specify `SDWebImageQueryMemoryData`, we query the memory image data asynchronously. Combined this mask as well to query the memory image data synchronously. + * @note Query data synchronously is not recommend, unless you want to ensure the image is loaded in the same runloop to avoid flashing during cell reusing. */ - SDWebImageQueryDiskSync = 1 << 14, + SDWebImageQueryMemoryDataSync = 1 << 14, + + /** + * By default, when the memory cache miss, we query the disk cache asynchronously. This mask can force to query disk cache (when memory cache miss) synchronously. + * @note These 3 query options can be combined together. For the full list about these masks combination, see wiki page. + * @note Query data synchronously is not recommend, unless you want to ensure the image is loaded in the same runloop to avoid flashing during cell reusing. + */ + SDWebImageQueryDiskDataSync = 1 << 15, /** * By default, when the cache missed, the image is load from the loader. This flag can prevent this to load from cache only. */ - SDWebImageFromCacheOnly = 1 << 15, + SDWebImageFromCacheOnly = 1 << 16, /** * By default, we query the cache before the image is load from the loader. This flag can prevent this to load from loader only. */ - SDWebImageFromLoaderOnly = 1 << 16, + SDWebImageFromLoaderOnly = 1 << 17, /** * By default, when you use `SDWebImageTransition` to do some view transition after the image load finished, this transition is only applied for image download from the network. This mask can force to apply view transition for memory and disk cache as well. */ - SDWebImageForceTransition = 1 << 17, + SDWebImageForceTransition = 1 << 18, /** * By default, we will decode the image in the background during cache query and download from the network. This can help to improve performance because when rendering image on the screen, it need to be firstly decoded. But this happen on the main queue by Core Animation. * However, this process may increase the memory usage as well. If you are experiencing a issue due to excessive memory consumption, This flag can prevent decode the image. */ - SDWebImageAvoidDecodeImage = 1 << 18, + SDWebImageAvoidDecodeImage = 1 << 19, /** * By default, we decode the animated image. This flag can force decode the first frame only and produece the static image. */ - SDWebImageDecodeFirstFrameOnly = 1 << 19, + SDWebImageDecodeFirstFrameOnly = 1 << 20, /** * By default, for `SDAnimatedImage`, we decode the animated image frame during rendering to reduce memory usage. However, you can specify to preload all frames into memory to reduce CPU usage when the animated image is shared by lots of imageViews. * This will actually trigger `preloadAllAnimatedImageFrames` in the background queue(Disk Cache & Download only). */ - SDWebImagePreloadAllFrames = 1 << 20 + SDWebImagePreloadAllFrames = 1 << 21 }; From 5df8f2a8b9f6550d7ea3a30a2fe1fce08cf9d1c6 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 10 May 2018 14:49:15 +0800 Subject: [PATCH 178/361] Fix image cache options issue, remove the unused `SDImageCacheTransformAnimatedImage` --- SDWebImage/SDImageCache.h | 11 +++-------- SDWebImage/SDImageCache.m | 3 ++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 1bb5b7cd..5275258a 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -31,24 +31,19 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { * images to a size compatible with the constrained memory of devices. */ SDImageCacheScaleDownLargeImages = 1 << 3, - /** - * We usually don't apply transform on animated images as most transformers could not manage animated images. - * Use this flag to transform them anyway. - */ - SDImageCacheTransformAnimatedImage = 1 << 4, /** * By default, we will decode the image in the background during cache query and download from the network. This can help to improve performance because when rendering image on the screen, it need to be firstly decoded. But this happen on the main queue by Core Animation. * However, this process may increase the memory usage as well. If you are experiencing a issue due to excessive memory consumption, This flag can prevent decode the image. */ - SDImageCacheAvoidDecodeImage = 1 << 5, + SDImageCacheAvoidDecodeImage = 1 << 4, /** * By default, we decode the animated image. This flag can force decode the first frame only and produece the static image. */ - SDImageCacheDecodeFirstFrameOnly = 1 << 6, + SDImageCacheDecodeFirstFrameOnly = 1 << 5, /** * By default, for `SDAnimatedImage`, we decode the animated image frame during rendering to reduce memory usage. This flag actually trigger `preloadAllAnimatedImageFrames = YES` after image load from disk cache */ - SDImageCachePreloadAllFrames = 1 << 7 + SDImageCachePreloadAllFrames = 1 << 6 }; /** diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 00744d8e..3ae01792 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -588,7 +588,8 @@ if (options & SDWebImageQueryMemoryData) cacheOptions |= SDImageCacheQueryMemoryData; if (options & SDWebImageQueryMemoryDataSync) cacheOptions |= SDImageCacheQueryMemoryDataSync; if (options & SDWebImageQueryDiskDataSync) cacheOptions |= SDImageCacheQueryDiskDataSync; - if (options & SDWebImageTransformAnimatedImage) cacheOptions |= SDImageCacheTransformAnimatedImage; + if (options & SDWebImageScaleDownLargeImages) cacheOptions |= SDImageCacheScaleDownLargeImages; + if (options & SDWebImageAvoidDecodeImage) cacheOptions |= SDImageCacheAvoidDecodeImage; if (options & SDWebImageDecodeFirstFrameOnly) cacheOptions |= SDImageCacheDecodeFirstFrameOnly; if (options & SDWebImagePreloadAllFrames) cacheOptions |= SDImageCachePreloadAllFrames; return [self queryCacheOperationForKey:key options:cacheOptions context:context done:completionBlock]; From 55584b7e919473225c95a9e38e6a113b681a87be Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 10 May 2018 14:49:48 +0800 Subject: [PATCH 179/361] Remove one unused header --- SDWebImage/SDImageCodersManager.m | 1 - 1 file changed, 1 deletion(-) diff --git a/SDWebImage/SDImageCodersManager.m b/SDWebImage/SDImageCodersManager.m index c1378d1d..33e1856f 100644 --- a/SDWebImage/SDImageCodersManager.m +++ b/SDWebImage/SDImageCodersManager.m @@ -15,7 +15,6 @@ #endif #import "NSImage+Compatibility.h" #import "UIImage+WebCache.h" -#import "SDWebImageDefine.h" #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); #define UNLOCK(lock) dispatch_semaphore_signal(lock); From a34133b86465b10578dc37747b02735ab61977f2 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 21 May 2018 14:56:55 +0800 Subject: [PATCH 180/361] Fix the progressive decoding bug on macOS. Including image orientation & SDAnimatedimageView --- SDWebImage/NSImage+Compatibility.m | 2 +- SDWebImage/SDAnimatedImageView.m | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/SDWebImage/NSImage+Compatibility.m b/SDWebImage/NSImage+Compatibility.m index 9672fa11..b42a2e09 100644 --- a/SDWebImage/NSImage+Compatibility.m +++ b/SDWebImage/NSImage+Compatibility.m @@ -46,7 +46,7 @@ // AppKit design is different from UIKit. Where CGImage based image rep does not respect to any orientation. Only data based image rep which contains the EXIF metadata can automatically detect orientation. // This should be nonnull, until the memory is exhausted cause `CGBitmapContextCreate` failed. CGImageRef rotatedCGImage = [SDImageCoderHelper CGImageCreateDecoded:cgImage orientation:orientation]; - imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; + imageRep = [[NSBitmapImageRep alloc] initWithCGImage:rotatedCGImage]; CGImageRelease(rotatedCGImage); } else { imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index af4a4e6c..0bf6bdc4 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -322,6 +322,9 @@ dispatch_semaphore_signal(self->_lock); } [self.layer setNeedsDisplay]; +#if SD_MAC + [self.layer displayIfNeeded]; // macOS's imageViewLayer is not equal to self.layer. But `[super setImage:]` will impliedly mark it needsDisplay. We call `[self.layer displayIfNeeded]` to immediately refresh the imageViewLayer to avoid flashing +#endif } } From 7d170d47d9cef345a49563274849b7629dfe0d8f Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Mon, 21 May 2018 17:51:07 +0800 Subject: [PATCH 181/361] Remove dispatch_queue_async_safe && optimize dispatch_main_async_safe --- SDWebImage/SDWebImageCompat.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index ce068071..81ca2211 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -87,15 +87,11 @@ typedef void(^SDWebImageNoParamsBlock)(void); FOUNDATION_EXPORT NSString *const SDWebImageErrorDomain; -#ifndef dispatch_queue_async_safe -#define dispatch_queue_async_safe(queue, block)\ - if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(queue)) == 0) {\ +#ifndef dispatch_main_async_safe +#define dispatch_main_async_safe(block)\ + if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(dispatch_get_main_queue())) {\ block();\ } else {\ - dispatch_async(queue, block);\ + dispatch_async(dispatch_get_main_queue(), block);\ } #endif - -#ifndef dispatch_main_async_safe -#define dispatch_main_async_safe(block) dispatch_queue_async_safe(dispatch_get_main_queue(), block) -#endif From 0471861d232e7b4d779dc04db9b53c2c4760bdec Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 24 May 2018 01:37:11 +0800 Subject: [PATCH 182/361] Fix that watchOS UIImage+WebCache does not mark as available and cause crash --- SDWebImage/UIImage+WebCache.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/UIImage+WebCache.m b/SDWebImage/UIImage+WebCache.m index 0ec283b1..412b6e7f 100644 --- a/SDWebImage/UIImage+WebCache.m +++ b/SDWebImage/UIImage+WebCache.m @@ -10,7 +10,7 @@ #import "NSImage+Compatibility.h" #import "objc/runtime.h" -#if SD_UIKIT +#if SD_UIKIT || SD_WATCH @implementation UIImage (WebCache) From 994bf0fe38db4804a42098c4ea7047125d6043e3 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 24 May 2018 01:48:08 +0800 Subject: [PATCH 183/361] Add the support for watchOS to use View Category method (sd_setImageWithURL:) on WKInterfaceImage --- .../InterfaceController.m | 8 +-- SDWebImage/SDWebImageCompat.h | 6 +++ SDWebImage/UIImageView+WebCache.h | 5 -- SDWebImage/UIImageView+WebCache.m | 5 -- SDWebImage/UIView+WebCache.h | 9 ++-- SDWebImage/UIView+WebCache.m | 49 ++++++++++++++----- SDWebImage/UIView+WebCacheOperation.h | 7 +-- SDWebImage/UIView+WebCacheOperation.m | 5 -- 8 files changed, 54 insertions(+), 40 deletions(-) diff --git a/Examples/SDWebImage Watch Demo Extension/InterfaceController.m b/Examples/SDWebImage Watch Demo Extension/InterfaceController.m index 31aeb716..521de388 100644 --- a/Examples/SDWebImage Watch Demo Extension/InterfaceController.m +++ b/Examples/SDWebImage Watch Demo Extension/InterfaceController.m @@ -29,9 +29,11 @@ // This method is called when watch view controller is about to be visible to user [super willActivate]; - NSString *urlString = @"https://nr-platform.s3.amazonaws.com/uploads/platform/published_extension/branding_icon/275/AmazonS3.png"; - [[SDWebImageManager sharedManager] loadImageWithURL:[NSURL URLWithString:urlString] options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { - self.imageInterface.image = image; + NSString *urlString = @"http://apng.onevcat.com/assets/elephant.png"; + WKInterfaceImage *imageInterface = self.imageInterface; + [imageInterface sd_setImageWithURL:[NSURL URLWithString:urlString] completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { + // `WKInterfaceImage` unlike `UIImageView`. Even the image is animated image, you should explicitly call `startAnimating` to play animation. + [imageInterface startAnimating]; }]; } diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index 7a68f34d..6fd79b6b 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -72,6 +72,12 @@ #endif #if SD_WATCH #import + #ifndef UIView + #define UIView WKInterfaceObject + #endif + #ifndef UIImageView + #define UIImageView WKInterfaceImage + #endif #endif #endif diff --git a/SDWebImage/UIImageView+WebCache.h b/SDWebImage/UIImageView+WebCache.h index 204c2278..1347f18d 100644 --- a/SDWebImage/UIImageView+WebCache.h +++ b/SDWebImage/UIImageView+WebCache.h @@ -7,9 +7,6 @@ */ #import "SDWebImageCompat.h" - -#if SD_UIKIT || SD_MAC - #import "SDWebImageManager.h" /** @@ -197,5 +194,3 @@ #endif @end - -#endif diff --git a/SDWebImage/UIImageView+WebCache.m b/SDWebImage/UIImageView+WebCache.m index 31bcabb9..63c19239 100644 --- a/SDWebImage/UIImageView+WebCache.m +++ b/SDWebImage/UIImageView+WebCache.m @@ -7,9 +7,6 @@ */ #import "UIImageView+WebCache.h" - -#if SD_UIKIT || SD_MAC - #import "objc/runtime.h" #import "UIView+WebCacheOperation.h" #import "UIView+WebCache.h" @@ -138,5 +135,3 @@ static char animationLoadOperationKey; #endif @end - -#endif diff --git a/SDWebImage/UIView+WebCache.h b/SDWebImage/UIView+WebCache.h index cf212146..d674d9a1 100644 --- a/SDWebImage/UIView+WebCache.h +++ b/SDWebImage/UIView+WebCache.h @@ -7,9 +7,6 @@ */ #import "SDWebImageCompat.h" - -#if SD_UIKIT || SD_MAC - #import "SDWebImageDefine.h" #import "SDWebImageManager.h" #import "SDWebImageTransition.h" @@ -77,6 +74,8 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima */ - (void)sd_cancelCurrentImageLoad; +#if SD_UIKIT || SD_MAC + #pragma mark - Image Transition /** @@ -94,6 +93,6 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima */ @property (nonatomic, strong, nullable) id sd_imageIndicator; -@end - #endif + +@end diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 2f5bc03f..ae27daeb 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -7,9 +7,6 @@ */ #import "UIView+WebCache.h" - -#if SD_UIKIT || SD_MAC - #import "objc/runtime.h" #import "UIView+WebCacheOperation.h" #import "SDWebImageError.h" @@ -79,8 +76,10 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; self.sd_imageProgress.totalUnitCount = 0; self.sd_imageProgress.completedUnitCount = 0; +#if SD_UIKIT || SD_MAC // check and start image indicator [self sd_startImageIndicator]; +#endif SDWebImageManager *manager; if ([context valueForKey:SDWebImageContextCustomManager]) { @@ -89,8 +88,6 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; manager = [SDWebImageManager sharedManager]; } - id imageIndicator = self.sd_imageIndicator; - __weak __typeof(self)wself = self; SDWebImageDownloaderProgressBlock combinedProgressBlock = ^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { wself.sd_imageProgress.totalUnitCount = expectedSize; @@ -98,12 +95,15 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; if (progressBlock) { progressBlock(receivedSize, expectedSize, targetURL); } +#if SD_UIKIT || SD_MAC + id imageIndicator = wself.sd_imageIndicator; if ([imageIndicator respondsToSelector:@selector(updateIndicatorProgress:)]) { double progress = wself.sd_imageProgress.fractionCompleted; dispatch_async(dispatch_get_main_queue(), ^{ [imageIndicator updateIndicatorProgress:progress]; }); } +#endif }; id operation = [manager loadImageWithURL:url options:options context:context progress:combinedProgressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { __strong __typeof (wself) sself = wself; @@ -114,10 +114,12 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; sself.sd_imageProgress.completedUnitCount = SDWebImageProgressUnitCountUnknown; } +#if SD_UIKIT || SD_MAC // check and stop image indicator if (finished) { [self sd_stopImageIndicator]; } +#endif BOOL shouldCallCompletedBlock = finished || (options & SDWebImageAvoidAutoSetImage); BOOL shouldNotSetImage = ((image && (options & SDWebImageAvoidAutoSetImage)) || @@ -152,16 +154,22 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; targetData = nil; } +#if SD_UIKIT || SD_MAC // check whether we should use the image transition SDWebImageTransition *transition = nil; if (finished && (options & SDWebImageForceTransition || cacheType == SDImageCacheTypeNone)) { transition = sself.sd_imageTransition; } +#endif if (group) { dispatch_group_enter(group); dispatch_main_async_safe(^{ +#if SD_UIKIT || SD_MAC [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL]; +#else + [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock]; +#endif }); // ensure completion block is called after custom setImage process finish dispatch_group_notify(group, dispatch_get_main_queue(), ^{ @@ -169,14 +177,20 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; }); } else { dispatch_main_async_safe(^{ +#if SD_UIKIT || SD_MAC [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL]; +#else + [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock]; +#endif callCompletedBlockClojure(); }); } }]; [self sd_setImageLoadOperation:operation forKey:validOperationKey]; } else { +#if SD_UIKIT || SD_MAC [self sd_stopImageIndicator]; +#endif dispatch_main_async_safe(^{ if (completedBlock) { NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidURL userInfo:@{NSLocalizedDescriptionKey : @"Image url is nil"}]; @@ -191,23 +205,31 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; } - (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock { +#if SD_UIKIT || SD_MAC [self sd_setImage:image imageData:imageData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:nil cacheType:0 imageURL:nil]; +#else + // watchOS does not support view transition. Simplify the logic + if (setImageBlock) { + setImageBlock(image, imageData); + } else if ([self isKindOfClass:[UIImageView class]]) { + UIImageView *imageView = (UIImageView *)self; + [imageView setImage:image]; + } +#endif } +#if SD_UIKIT || SD_MAC - (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock transition:(SDWebImageTransition *)transition cacheType:(SDImageCacheType)cacheType imageURL:(NSURL *)imageURL { UIView *view = self; SDSetImageBlock finalSetImageBlock; if (setImageBlock) { finalSetImageBlock = setImageBlock; - } -#if SD_UIKIT || SD_MAC - else if ([view isKindOfClass:[UIImageView class]]) { + } else if ([view isKindOfClass:[UIImageView class]]) { UIImageView *imageView = (UIImageView *)view; finalSetImageBlock = ^(UIImage *setImage, NSData *setImageData) { imageView.image = setImage; }; } -#endif #if SD_UIKIT else if ([view isKindOfClass:[UIButton class]]) { UIButton *button = (UIButton *)view; @@ -273,15 +295,20 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; } } } +#endif - (void)sd_setNeedsLayout { #if SD_UIKIT [self setNeedsLayout]; #elif SD_MAC [self setNeedsLayout:YES]; +#elif SD_WATCH + // Do nothing because WatchKit automatically layout the view after property change #endif } +#if SD_UIKIT || SD_MAC + #pragma mark - Image Transition - (SDWebImageTransition *)sd_imageTransition { return objc_getAssociatedObject(self, @selector(sd_imageTransition)); @@ -340,6 +367,6 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; }); } -@end - #endif + +@end diff --git a/SDWebImage/UIView+WebCacheOperation.h b/SDWebImage/UIView+WebCacheOperation.h index 18361829..65872521 100644 --- a/SDWebImage/UIView+WebCacheOperation.h +++ b/SDWebImage/UIView+WebCacheOperation.h @@ -7,10 +7,7 @@ */ #import "SDWebImageCompat.h" - -#if SD_UIKIT || SD_MAC - -#import "SDWebImageManager.h" +#import "SDWebImageOperation.h" // These methods are used to support canceling for UIView image loading, it's designed to be used internal but not external. // All the stored operations are weak, so it will be dalloced after image loading finished. If you need to store operations, use your own class to keep a strong reference for them. @@ -47,5 +44,3 @@ - (void)sd_removeImageLoadOperationWithKey:(nullable NSString *)key; @end - -#endif diff --git a/SDWebImage/UIView+WebCacheOperation.m b/SDWebImage/UIView+WebCacheOperation.m index b4f25edc..d83c8e0c 100644 --- a/SDWebImage/UIView+WebCacheOperation.m +++ b/SDWebImage/UIView+WebCacheOperation.m @@ -7,9 +7,6 @@ */ #import "UIView+WebCacheOperation.h" - -#if SD_UIKIT || SD_MAC - #import "objc/runtime.h" static char loadOperationKey; @@ -80,5 +77,3 @@ typedef NSMapTable> SDOperationsDictionary; } @end - -#endif From bf3c0b42dc84d75fc84c6e886835babe74655e94 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 30 May 2018 21:42:40 +0800 Subject: [PATCH 184/361] A little improvement for image progress code for UIView+WebCache.m --- SDWebImage/UIView+WebCache.m | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index ae27daeb..dfe1ae7b 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -79,6 +79,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; #if SD_UIKIT || SD_MAC // check and start image indicator [self sd_startImageIndicator]; + id imageIndicator = self.sd_imageIndicator; #endif SDWebImageManager *manager; @@ -90,15 +91,16 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; __weak __typeof(self)wself = self; SDWebImageDownloaderProgressBlock combinedProgressBlock = ^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { - wself.sd_imageProgress.totalUnitCount = expectedSize; - wself.sd_imageProgress.completedUnitCount = receivedSize; + __strong __typeof (wself) sself = wself; + NSProgress *imageProgress = sself.sd_imageProgress; + imageProgress.totalUnitCount = expectedSize; + imageProgress.completedUnitCount = receivedSize; if (progressBlock) { progressBlock(receivedSize, expectedSize, targetURL); } #if SD_UIKIT || SD_MAC - id imageIndicator = wself.sd_imageIndicator; if ([imageIndicator respondsToSelector:@selector(updateIndicatorProgress:)]) { - double progress = wself.sd_imageProgress.fractionCompleted; + double progress = imageProgress.fractionCompleted; dispatch_async(dispatch_get_main_queue(), ^{ [imageIndicator updateIndicatorProgress:progress]; }); From f96c94ef7da24f622674fa45b13b045e90f41f06 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 17 May 2018 12:00:31 +0800 Subject: [PATCH 185/361] Renaming all `SDWebImageLoader` -> `SDImageLoader` --- SDWebImage.xcodeproj/project.pbxproj | 112 +++++++++--------- .../{SDWebImageLoader.h => SDImageLoader.h} | 19 ++- .../{SDWebImageLoader.m => SDImageLoader.m} | 12 +- ...adersManager.h => SDImageLoadersManager.h} | 12 +- ...adersManager.m => SDImageLoadersManager.m} | 36 +++--- SDWebImage/SDWebImageDownloader.h | 12 +- SDWebImage/SDWebImageDownloader.m | 4 +- SDWebImage/SDWebImageDownloaderOperation.m | 4 +- SDWebImage/SDWebImageManager.h | 8 +- SDWebImage/SDWebImageManager.m | 14 +-- WebImage/SDWebImage.h | 4 +- 11 files changed, 118 insertions(+), 119 deletions(-) rename SDWebImage/{SDWebImageLoader.h => SDImageLoader.h} (81%) rename SDWebImage/{SDWebImageLoader.m => SDImageLoader.m} (88%) rename SDWebImage/{SDWebImageLoadersManager.h => SDImageLoadersManager.h} (59%) rename SDWebImage/{SDWebImageLoadersManager.m => SDImageLoadersManager.m} (64%) diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index ae449009..5e5b8210 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -49,30 +49,30 @@ 320CAE1E2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; 320CAE1F2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; 320CAE202086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; - 321B37812083290E00C0EA77 /* SDWebImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37822083290E00C0EA77 /* SDWebImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37832083290E00C0EA77 /* SDWebImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37842083290E00C0EA77 /* SDWebImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37852083290E00C0EA77 /* SDWebImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37862083290E00C0EA77 /* SDWebImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37872083290E00C0EA77 /* SDWebImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */; }; - 321B37882083290E00C0EA77 /* SDWebImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */; }; - 321B37892083290E00C0EA77 /* SDWebImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */; }; - 321B378A2083290E00C0EA77 /* SDWebImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */; }; - 321B378B2083290E00C0EA77 /* SDWebImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */; }; - 321B378C2083290E00C0EA77 /* SDWebImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */; }; - 321B378D2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B378E2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B378F2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37902083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37912083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37922083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 321B37932083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */; }; - 321B37942083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */; }; - 321B37952083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */; }; - 321B37962083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */; }; - 321B37972083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */; }; - 321B37982083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */; }; + 321B37812083290E00C0EA77 /* SDImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37822083290E00C0EA77 /* SDImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37832083290E00C0EA77 /* SDImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37842083290E00C0EA77 /* SDImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37852083290E00C0EA77 /* SDImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37862083290E00C0EA77 /* SDImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377D2083290D00C0EA77 /* SDImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37872083290E00C0EA77 /* SDImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDImageLoader.m */; }; + 321B37882083290E00C0EA77 /* SDImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDImageLoader.m */; }; + 321B37892083290E00C0EA77 /* SDImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDImageLoader.m */; }; + 321B378A2083290E00C0EA77 /* SDImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDImageLoader.m */; }; + 321B378B2083290E00C0EA77 /* SDImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDImageLoader.m */; }; + 321B378C2083290E00C0EA77 /* SDImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B377E2083290D00C0EA77 /* SDImageLoader.m */; }; + 321B378D2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B378E2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B378F2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37902083290E00C0EA77 /* SDImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37912083290E00C0EA77 /* SDImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37922083290E00C0EA77 /* SDImageLoadersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 321B37932083290E00C0EA77 /* SDImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDImageLoadersManager.m */; }; + 321B37942083290E00C0EA77 /* SDImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDImageLoadersManager.m */; }; + 321B37952083290E00C0EA77 /* SDImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDImageLoadersManager.m */; }; + 321B37962083290E00C0EA77 /* SDImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDImageLoadersManager.m */; }; + 321B37972083290E00C0EA77 /* SDImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDImageLoadersManager.m */; }; + 321B37982083290E00C0EA77 /* SDImageLoadersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 321B37802083290E00C0EA77 /* SDImageLoadersManager.m */; }; 321DB3612011D4D70015D2CB /* NSButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 321DB3622011D4D70015D2CB /* NSButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */; }; 321E60861F38E8C800405457 /* SDImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1545,10 +1545,10 @@ 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImageRep.m; sourceTree = ""; }; 320CAE132086F50500CFFC80 /* SDWebImageError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageError.h; sourceTree = ""; }; 320CAE142086F50500CFFC80 /* SDWebImageError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageError.m; sourceTree = ""; }; - 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageLoader.h; sourceTree = ""; }; - 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageLoader.m; sourceTree = ""; }; - 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageLoadersManager.h; sourceTree = ""; }; - 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageLoadersManager.m; sourceTree = ""; }; + 321B377D2083290D00C0EA77 /* SDImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageLoader.h; sourceTree = ""; }; + 321B377E2083290D00C0EA77 /* SDImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageLoader.m; sourceTree = ""; }; + 321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageLoadersManager.h; sourceTree = ""; }; + 321B37802083290E00C0EA77 /* SDImageLoadersManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageLoadersManager.m; sourceTree = ""; }; 321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSButton+WebCache.h"; path = "SDWebImage/NSButton+WebCache.h"; sourceTree = ""; }; 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSButton+WebCache.m"; path = "SDWebImage/NSButton+WebCache.m"; sourceTree = ""; }; 321E60841F38E8C800405457 /* SDImageCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageCoder.h; sourceTree = ""; }; @@ -2185,10 +2185,10 @@ 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */, 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */, 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */, - 321B377D2083290D00C0EA77 /* SDWebImageLoader.h */, - 321B377E2083290D00C0EA77 /* SDWebImageLoader.m */, - 321B377F2083290E00C0EA77 /* SDWebImageLoadersManager.h */, - 321B37802083290E00C0EA77 /* SDWebImageLoadersManager.m */, + 321B377D2083290D00C0EA77 /* SDImageLoader.h */, + 321B377E2083290D00C0EA77 /* SDImageLoader.m */, + 321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */, + 321B37802083290E00C0EA77 /* SDImageLoadersManager.m */, ); name = Downloader; sourceTree = ""; @@ -2398,7 +2398,7 @@ 32B9B53A206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AD2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 80377C4A1F2F666300F89830 /* bit_writer_utils.h in Headers */, - 321B37902083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, + 321B37902083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, 323F8BE71F38EF770092B609 /* vp8li_enc.h in Headers */, 329A185C1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 4369C27A1D9807EC007E863A /* UIView+WebCache.h in Headers */, @@ -2441,7 +2441,7 @@ 328BB6D02082581100760D6C /* SDMemoryCache.h in Headers */, 321E60891F38E8C800405457 /* SDImageCoder.h in Headers */, 00733A721BC4880E00A5A117 /* UIView+WebCacheOperation.h in Headers */, - 321B37842083290E00C0EA77 /* SDWebImageLoader.h in Headers */, + 321B37842083290E00C0EA77 /* SDImageLoader.h in Headers */, 80377C481F2F666300F89830 /* bit_reader_utils.h in Headers */, 80377C511F2F666300F89830 /* huffman_encode_utils.h in Headers */, 32484778201775F600AF9E5A /* SDAnimatedImage.h in Headers */, @@ -2520,7 +2520,7 @@ 4314D16F1D0E0E3B004B36C9 /* NSData+ImageContentType.h in Headers */, 80377C121F2F666300F89830 /* bit_reader_inl_utils.h in Headers */, 4314D1701D0E0E3B004B36C9 /* mux.h in Headers */, - 321B378E2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, + 321B378E2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, 321E60871F38E8C800405457 /* SDImageCoder.h in Headers */, 80377EA21F2F66D400F89830 /* vp8i_dec.h in Headers */, 320CAE162086F50500CFFC80 /* SDWebImageError.h in Headers */, @@ -2529,7 +2529,7 @@ 80377C211F2F666300F89830 /* quant_levels_dec_utils.h in Headers */, 4314D1721D0E0E3B004B36C9 /* SDWebImageCompat.h in Headers */, 32484776201775F600AF9E5A /* SDAnimatedImage.h in Headers */, - 321B37822083290E00C0EA77 /* SDWebImageLoader.h in Headers */, + 321B37822083290E00C0EA77 /* SDImageLoader.h in Headers */, 80377C251F2F666300F89830 /* random_utils.h in Headers */, 80377D4F1F2F66A700F89830 /* lossless.h in Headers */, 80377D511F2F66A700F89830 /* msa_macro.h in Headers */, @@ -2585,7 +2585,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 321B37912083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, + 321B37912083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, 80377C791F2F666400F89830 /* utils.h in Headers */, 328BB6A02081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */, 323F8B721F38EF770092B609 /* delta_palettization_enc.h in Headers */, @@ -2598,7 +2598,7 @@ 32484767201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */, 80377C601F2F666400F89830 /* bit_reader_inl_utils.h in Headers */, 32FDE89920888726008D7530 /* UIImage+WebP.h in Headers */, - 321B37852083290E00C0EA77 /* SDWebImageLoader.h in Headers */, + 321B37852083290E00C0EA77 /* SDImageLoader.h in Headers */, 329A185D1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, 431BB6DC1D06D2C1006A3455 /* UIButton+WebCache.h in Headers */, 431BB6E11D06D2C1006A3455 /* SDWebImage.h in Headers */, @@ -2693,7 +2693,7 @@ 32B9B53C206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AF2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 4397D2BA1D0DDD8C00BB2784 /* demux.h in Headers */, - 321B37922083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, + 321B37922083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, 80377C8F1F2F666400F89830 /* rescaler_utils.h in Headers */, 4397D2BD1D0DDD8C00BB2784 /* types.h in Headers */, 4397D2C01D0DDD8C00BB2784 /* SDWebImage.h in Headers */, @@ -2739,7 +2739,7 @@ 328BB6D22082581100760D6C /* SDMemoryCache.h in Headers */, 323F8BDD1F38EF770092B609 /* vp8i_enc.h in Headers */, 323F8B671F38EF770092B609 /* cost_enc.h in Headers */, - 321B37862083290E00C0EA77 /* SDWebImageLoader.h in Headers */, + 321B37862083290E00C0EA77 /* SDImageLoader.h in Headers */, 80377EE11F2F66D500F89830 /* vp8_dec.h in Headers */, 80377EE41F2F66D500F89830 /* vp8li_dec.h in Headers */, 80377C931F2F666400F89830 /* utils.h in Headers */, @@ -2794,7 +2794,7 @@ 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */, 328BB6AC2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */, 80377C301F2F666300F89830 /* bit_writer_utils.h in Headers */, - 321B378F2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, + 321B378F2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, 431739541CDFC8B70008FEB9 /* types.h in Headers */, 323F8BE61F38EF770092B609 /* vp8li_enc.h in Headers */, 329A185B1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, @@ -2839,7 +2839,7 @@ 328BB6CF2082581100760D6C /* SDMemoryCache.h in Headers */, 321E60881F38E8C800405457 /* SDImageCoder.h in Headers */, 4A2CAE371AB4BB7500B6BC39 /* UIView+WebCacheOperation.h in Headers */, - 321B37832083290E00C0EA77 /* SDWebImageLoader.h in Headers */, + 321B37832083290E00C0EA77 /* SDImageLoader.h in Headers */, 80377C2E1F2F666300F89830 /* bit_reader_utils.h in Headers */, 80377C371F2F666300F89830 /* huffman_encode_utils.h in Headers */, 32484777201775F600AF9E5A /* SDAnimatedImage.h in Headers */, @@ -2931,7 +2931,7 @@ 321E60BE1F38E91700405457 /* UIImage+ForceDecode.h in Headers */, 5376131E155AD0D5005750A4 /* SDWebImagePrefetcher.h in Headers */, 32F7C06F2030114C00873181 /* SDImageTransformer.h in Headers */, - 321B378D2083290E00C0EA77 /* SDWebImageLoadersManager.h in Headers */, + 321B378D2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, 32FDE8A220888789008D7530 /* SDWebImage.h in Headers */, 324DF4B4200A14DC008A84CC /* SDWebImageDefine.h in Headers */, 80377CE11F2F66A100F89830 /* common_sse2.h in Headers */, @@ -2958,7 +2958,7 @@ 32FDE88F20888726008D7530 /* SDImageWebPCoder.h in Headers */, 320CAE152086F50500CFFC80 /* SDWebImageError.h in Headers */, 323F8B861F38EF770092B609 /* histogram_enc.h in Headers */, - 321B37812083290E00C0EA77 /* SDWebImageLoader.h in Headers */, + 321B37812083290E00C0EA77 /* SDImageLoader.h in Headers */, 323F8BF61F38EF770092B609 /* animi.h in Headers */, 321E60861F38E8C800405457 /* SDImageCoder.h in Headers */, 80377C0D1F2F665300F89830 /* rescaler_utils.h in Headers */, @@ -3259,7 +3259,7 @@ 80377DD71F2F66A700F89830 /* lossless_sse2.c in Sources */, 80377DA81F2F66A700F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, 80377DB11F2F66A700F89830 /* cost_mips_dsp_r2.c in Sources */, - 321B37962083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */, + 321B37962083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, 80377C581F2F666300F89830 /* random_utils.c in Sources */, 323F8B591F38EF770092B609 /* config_enc.c in Sources */, 80377DE91F2F66A700F89830 /* yuv_mips32.c in Sources */, @@ -3319,7 +3319,7 @@ 80377C561F2F666300F89830 /* quant_levels_utils.c in Sources */, 323F8BCF1F38EF770092B609 /* token_enc.c in Sources */, 80377DD11F2F66A700F89830 /* lossless_enc_sse2.c in Sources */, - 321B378A2083290E00C0EA77 /* SDWebImageLoader.m in Sources */, + 321B378A2083290E00C0EA77 /* SDImageLoader.m in Sources */, 32484772201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 323F8C1D1F38EF770092B609 /* muxread.c in Sources */, 807A12311F89636300EC2A9B /* SDImageCodersManager.m in Sources */, @@ -3463,7 +3463,7 @@ 80377E9C1F2F66D400F89830 /* idec_dec.c in Sources */, 323F8B7B1F38EF770092B609 /* frame_enc.c in Sources */, 80377D211F2F66A700F89830 /* alpha_processing_sse41.c in Sources */, - 321B37942083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */, + 321B37942083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, 323F8B8D1F38EF770092B609 /* iterator_enc.c in Sources */, 3248475E201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 80377D481F2F66A700F89830 /* lossless_enc_sse41.c in Sources */, @@ -3524,7 +3524,7 @@ 80377E991F2F66D400F89830 /* buffer_dec.c in Sources */, 80377C201F2F666300F89830 /* quant_levels_dec_utils.c in Sources */, 32F7C07F2030719600873181 /* UIImage+Transform.m in Sources */, - 321B37882083290E00C0EA77 /* SDWebImageLoader.m in Sources */, + 321B37882083290E00C0EA77 /* SDImageLoader.m in Sources */, 80377D471F2F66A700F89830 /* lossless_enc_sse2.c in Sources */, 80377C1E1F2F666300F89830 /* huffman_utils.c in Sources */, ); @@ -3630,7 +3630,7 @@ 80377DF01F2F66A800F89830 /* alpha_processing_sse41.c in Sources */, 80377ECC1F2F66D500F89830 /* idec_dec.c in Sources */, 323F8B7E1F38EF770092B609 /* frame_enc.c in Sources */, - 321B37972083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */, + 321B37972083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, 80377E171F2F66A800F89830 /* lossless_enc_sse41.c in Sources */, 32484761201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 323F8B901F38EF770092B609 /* iterator_enc.c in Sources */, @@ -3690,7 +3690,7 @@ 80377EC91F2F66D500F89830 /* buffer_dec.c in Sources */, 80377C6C1F2F666400F89830 /* huffman_utils.c in Sources */, 32F7C0822030719600873181 /* UIImage+Transform.m in Sources */, - 321B378B2083290E00C0EA77 /* SDWebImageLoader.m in Sources */, + 321B378B2083290E00C0EA77 /* SDImageLoader.m in Sources */, 80377E161F2F66A800F89830 /* lossless_enc_sse2.c in Sources */, 431BB6C71D06D2C1006A3455 /* UIImageView+HighlightedWebCache.m in Sources */, ); @@ -3780,7 +3780,7 @@ 32F21B5C20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 32D122292080B2EB003685A3 /* SDImageCacheDefine.m in Sources */, 80377E3B1F2F66A800F89830 /* cost_mips_dsp_r2.c in Sources */, - 321B378C2083290E00C0EA77 /* SDWebImageLoader.m in Sources */, + 321B378C2083290E00C0EA77 /* SDImageLoader.m in Sources */, 4397D29B1D0DDD8C00BB2784 /* SDWebImageDownloader.m in Sources */, 80377E711F2F66A800F89830 /* upsampling.c in Sources */, 328BB6A72081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */, @@ -3857,7 +3857,7 @@ 323F8B851F38EF770092B609 /* histogram_enc.c in Sources */, 80377EE51F2F66D500F89830 /* webp_dec.c in Sources */, 4397D2B01D0DDD8C00BB2784 /* SDImageCache.m in Sources */, - 321B37982083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */, + 321B37982083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, 32F7C07A2030114C00873181 /* SDImageTransformer.m in Sources */, 80377E4F1F2F66A800F89830 /* enc_sse41.c in Sources */, 80377E701F2F66A800F89830 /* upsampling_sse2.c in Sources */, @@ -3928,7 +3928,7 @@ 80377D921F2F66A700F89830 /* lossless_sse2.c in Sources */, 80377D631F2F66A700F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, 80377D6C1F2F66A700F89830 /* cost_mips_dsp_r2.c in Sources */, - 321B37952083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */, + 321B37952083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, 4A2CAE361AB4BB7500B6BC39 /* UIImageView+WebCache.m in Sources */, 323F8B581F38EF770092B609 /* config_enc.c in Sources */, 43C892A21D9D6DDD0022038D /* demux.c in Sources */, @@ -3988,7 +3988,7 @@ 4A2CAE191AB4BB6400B6BC39 /* SDWebImageCompat.m in Sources */, 80377DA11F2F66A700F89830 /* upsampling_sse2.c in Sources */, 323F8BCE1F38EF770092B609 /* token_enc.c in Sources */, - 321B37892083290E00C0EA77 /* SDWebImageLoader.m in Sources */, + 321B37892083290E00C0EA77 /* SDImageLoader.m in Sources */, 32484771201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 80377C3C1F2F666300F89830 /* quant_levels_utils.c in Sources */, 323F8C1C1F38EF770092B609 /* muxread.c in Sources */, @@ -4099,7 +4099,7 @@ 80377CD91F2F66A100F89830 /* alpha_processing_mips_dsp_r2.c in Sources */, 80377CE21F2F66A100F89830 /* cost_mips_dsp_r2.c in Sources */, 5376130B155AD0D5005750A4 /* SDWebImageDownloader.m in Sources */, - 321B37932083290E00C0EA77 /* SDWebImageLoadersManager.m in Sources */, + 321B37932083290E00C0EA77 /* SDImageLoadersManager.m in Sources */, 323F8B561F38EF770092B609 /* config_enc.c in Sources */, 43C8929B1D9D6DD70022038D /* demux.c in Sources */, 80377D1A1F2F66A100F89830 /* yuv_mips32.c in Sources */, @@ -4158,7 +4158,7 @@ 80377D171F2F66A100F89830 /* upsampling_sse2.c in Sources */, 323F8BCC1F38EF770092B609 /* token_enc.c in Sources */, 80377C081F2F665300F89830 /* quant_levels_utils.c in Sources */, - 321B37872083290E00C0EA77 /* SDWebImageLoader.m in Sources */, + 321B37872083290E00C0EA77 /* SDImageLoader.m in Sources */, 3248476F201775F600AF9E5A /* SDAnimatedImage.m in Sources */, 323F8C1A1F38EF770092B609 /* muxread.c in Sources */, 807A122E1F89636300EC2A9B /* SDImageCodersManager.m in Sources */, diff --git a/SDWebImage/SDWebImageLoader.h b/SDWebImage/SDImageLoader.h similarity index 81% rename from SDWebImage/SDWebImageLoader.h rename to SDWebImage/SDImageLoader.h index 250e90ec..e84843d0 100644 --- a/SDWebImage/SDWebImageLoader.h +++ b/SDWebImage/SDImageLoader.h @@ -10,9 +10,8 @@ #import "SDWebImageDefine.h" #import "SDWebImageOperation.h" -@protocol SDProgressiveImageCoder; -typedef void(^SDWebImageLoaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL); -typedef void(^SDWebImageLoaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished); +typedef void(^SDImageLoaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL); +typedef void(^SDImageLoaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished); #pragma mark - Context Options @@ -35,7 +34,7 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextLoader @param context The context arg from the input @return The decoded image for current image data load from the network */ -FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, SDWebImageOptions options, SDWebImageContext * _Nullable context); +FOUNDATION_EXPORT UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, SDWebImageOptions options, SDWebImageContext * _Nullable context); /** This is the built-in decoding process for image progressive download from network. It's used when `SDWebImageProgressiveLoad` option is set. (It's not required when your loader does not support progressive image loading) @@ -49,16 +48,16 @@ FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _ @param context The context arg from the input @return The decoded progressive image for current image data load from the network */ -FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, BOOL finished, id _Nonnull operation, SDWebImageOptions options, SDWebImageContext * _Nullable context); +FOUNDATION_EXPORT UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, BOOL finished, id _Nonnull operation, SDWebImageOptions options, SDWebImageContext * _Nullable context); -#pragma mark - SDWebImageLoader +#pragma mark - SDImageLoader // This is the protocol to specify custom image load process. You can create your own class to conform this protocol and use as a image loader to load image from network or any avaiable remote resources defined by yourself. -// If you want to implement custom loader for image download from network or local file, you just need to concentrate on image data download only. After the download finish, call `SDWebImageLoaderDecodeImageData` or `SDWebImageLoaderDecodeProgressiveImageData` to use the built-in decoding process and produce image (Remember to call in the global queue). And finally callback the completion block. +// If you want to implement custom loader for image download from network or local file, you just need to concentrate on image data download only. After the download finish, call `SDImageLoaderDecodeImageData` or `SDImageLoaderDecodeProgressiveImageData` to use the built-in decoding process and produce image (Remember to call in the global queue). And finally callback the completion block. // If you directlly get the image instance using some third-party SDKs, such as image directlly from Photos framework. You can process the image data and image instance by yourself without that built-in decoding process. And finally callback the completion block. // @note It's your responsibility to load the image in the desired global queue(to avoid block main queue). We do not dispatch these method call in a global queue but just from the call queue (For `SDWebImageManager`, it typically call from the main queue). -@protocol SDWebImageLoader +@protocol SDImageLoader /** Whether current image loader supports to load the provide image URL. @@ -83,7 +82,7 @@ FOUNDATION_EXPORT UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData - (nullable id)loadImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageLoaderProgressBlock)progressBlock - completed:(nullable SDWebImageLoaderCompletedBlock)completedBlock; + progress:(nullable SDImageLoaderProgressBlock)progressBlock + completed:(nullable SDImageLoaderCompletedBlock)completedBlock; @end diff --git a/SDWebImage/SDWebImageLoader.m b/SDWebImage/SDImageLoader.m similarity index 88% rename from SDWebImage/SDWebImageLoader.m rename to SDWebImage/SDImageLoader.m index 4994efe7..cb7598a2 100644 --- a/SDWebImage/SDWebImageLoader.m +++ b/SDWebImage/SDImageLoader.m @@ -6,7 +6,7 @@ * file that was distributed with this source code. */ -#import "SDWebImageLoader.h" +#import "SDImageLoader.h" #import "SDWebImageCacheKeyFilter.h" #import "SDImageCodersManager.h" #import "SDImageCoderHelper.h" @@ -14,9 +14,9 @@ #import "UIImage+WebCache.h" #import "objc/runtime.h" -static void * SDWebImageLoaderProgressiveCoderKey = &SDWebImageLoaderProgressiveCoderKey; +static void * SDImageLoaderProgressiveCoderKey = &SDImageLoaderProgressiveCoderKey; -UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, SDWebImageOptions options, SDWebImageContext * _Nullable context) { +UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, SDWebImageOptions options, SDWebImageContext * _Nullable context) { NSCParameterAssert(imageData); NSCParameterAssert(imageURL); @@ -72,7 +72,7 @@ UIImage * _Nullable SDWebImageLoaderDecodeImageData(NSData * _Nonnull imageData, return image; } -UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, BOOL finished, id _Nonnull operation, SDWebImageOptions options, SDWebImageContext * _Nullable context) { +UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, BOOL finished, id _Nonnull operation, SDWebImageOptions options, SDWebImageContext * _Nullable context) { NSCParameterAssert(imageData); NSCParameterAssert(imageURL); NSCParameterAssert(operation); @@ -91,7 +91,7 @@ UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull if (scale < 1) { scale = 1; } - id progressiveCoder = objc_getAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey); + id progressiveCoder = objc_getAssociatedObject(operation, SDImageLoaderProgressiveCoderKey); if (!progressiveCoder) { // We need to create a new instance for progressive decoding to avoid conflicts for (idcoder in [SDImageCodersManager sharedManager].coders.reverseObjectEnumerator) { @@ -101,7 +101,7 @@ UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull break; } } - objc_setAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey, progressiveCoder, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(operation, SDImageLoaderProgressiveCoderKey, progressiveCoder, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } // If we can't find any progressive coder, disable progressive download if (!progressiveCoder) { diff --git a/SDWebImage/SDWebImageLoadersManager.h b/SDWebImage/SDImageLoadersManager.h similarity index 59% rename from SDWebImage/SDWebImageLoadersManager.h rename to SDWebImage/SDImageLoadersManager.h index 7b59b592..1e278628 100644 --- a/SDWebImage/SDWebImageLoadersManager.h +++ b/SDWebImage/SDImageLoadersManager.h @@ -6,29 +6,29 @@ * file that was distributed with this source code. */ -#import "SDWebImageLoader.h" +#import "SDImageLoader.h" -@interface SDWebImageLoadersManager : NSObject +@interface SDImageLoadersManager : NSObject -@property (nonatomic, class, readonly, nonnull) SDWebImageLoadersManager *sharedManager; +@property (nonatomic, class, readonly, nonnull) SDImageLoadersManager *sharedManager; /** All image loaders in manager. The loaders array is a priority queue, which means the later added loader will have the highest priority */ -@property (nonatomic, copy, readwrite, nullable) NSArray>* loaders; +@property (nonatomic, copy, readwrite, nullable) NSArray>* loaders; /** Add a new image loader to the end of loaders array. Which has the highest priority. @param loader loader */ -- (void)addLoader:(nonnull id)loader; +- (void)addLoader:(nonnull id)loader; /** Remove a image loader in the loaders array. @param loader loader */ -- (void)removeLoader:(nonnull id)loader; +- (void)removeLoader:(nonnull id)loader; @end diff --git a/SDWebImage/SDWebImageLoadersManager.m b/SDWebImage/SDImageLoadersManager.m similarity index 64% rename from SDWebImage/SDWebImageLoadersManager.m rename to SDWebImage/SDImageLoadersManager.m index 9e5850de..123113bf 100644 --- a/SDWebImage/SDWebImageLoadersManager.m +++ b/SDWebImage/SDImageLoadersManager.m @@ -6,25 +6,25 @@ * file that was distributed with this source code. */ -#import "SDWebImageLoadersManager.h" +#import "SDImageLoadersManager.h" #import "SDWebImageDownloader.h" #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); #define UNLOCK(lock) dispatch_semaphore_signal(lock); -@interface SDWebImageLoadersManager () +@interface SDImageLoadersManager () @property (nonatomic, strong, nonnull) dispatch_semaphore_t loadersLock; @end -@implementation SDWebImageLoadersManager +@implementation SDImageLoadersManager -+ (SDWebImageLoadersManager *)sharedManager { ++ (SDImageLoadersManager *)sharedManager { static dispatch_once_t onceToken; - static SDWebImageLoadersManager *manager; + static SDImageLoadersManager *manager; dispatch_once(&onceToken, ^{ - manager = [[SDWebImageLoadersManager alloc] init]; + manager = [[SDImageLoadersManager alloc] init]; }); return manager; } @@ -41,12 +41,12 @@ #pragma mark - Loader Property -- (void)addLoader:(id)loader { - if (![loader conformsToProtocol:@protocol(SDWebImageLoader)]) { +- (void)addLoader:(id)loader { + if (![loader conformsToProtocol:@protocol(SDImageLoader)]) { return; } LOCK(self.loadersLock); - NSMutableArray> *mutableLoaders = [self.loaders mutableCopy]; + NSMutableArray> *mutableLoaders = [self.loaders mutableCopy]; if (!mutableLoaders) { mutableLoaders = [NSMutableArray array]; } @@ -55,24 +55,24 @@ UNLOCK(self.loadersLock); } -- (void)removeLoader:(id)loader { - if (![loader conformsToProtocol:@protocol(SDWebImageLoader)]) { +- (void)removeLoader:(id)loader { + if (![loader conformsToProtocol:@protocol(SDImageLoader)]) { return; } LOCK(self.loadersLock); - NSMutableArray> *mutableLoaders = [self.loaders mutableCopy]; + NSMutableArray> *mutableLoaders = [self.loaders mutableCopy]; [mutableLoaders removeObject:loader]; self.loaders = [mutableLoaders copy]; UNLOCK(self.loadersLock); } -#pragma mark - SDWebImageLoader +#pragma mark - SDImageLoader - (BOOL)canLoadWithURL:(nullable NSURL *)url { LOCK(self.loadersLock); - NSArray> *loaders = self.loaders; + NSArray> *loaders = self.loaders; UNLOCK(self.loadersLock); - for (id loader in loaders.reverseObjectEnumerator) { + for (id loader in loaders.reverseObjectEnumerator) { if ([loader canLoadWithURL:url]) { return YES; } @@ -80,14 +80,14 @@ return NO; } -- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDWebImageLoaderProgressBlock)progressBlock completed:(SDWebImageLoaderCompletedBlock)completedBlock { +- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDImageLoaderCompletedBlock)completedBlock { if (!url) { return nil; } LOCK(self.loadersLock); - NSArray> *loaders = self.loaders; + NSArray> *loaders = self.loaders; UNLOCK(self.loadersLock); - for (id loader in loaders.reverseObjectEnumerator) { + for (id loader in loaders.reverseObjectEnumerator) { if ([loader respondsToSelector:@selector(loadImageWithURL:options:context:progress:completed:)]) { return [loader loadImageWithURL:url options:options context:context progress:progressBlock completed:completedBlock]; } diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 441941d3..4996f7c0 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -12,7 +12,7 @@ #import "SDWebImageOperation.h" #import "SDWebImageDownloaderConfig.h" #import "SDWebImageDownloaderRequestModifier.h" -#import "SDWebImageLoader.h" +#import "SDImageLoader.h" typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { /** @@ -88,8 +88,8 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStartNotification; FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStopNotification; -typedef SDWebImageLoaderProgressBlock SDWebImageDownloaderProgressBlock; -typedef SDWebImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock; +typedef SDImageLoaderProgressBlock SDWebImageDownloaderProgressBlock; +typedef SDImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock; /** * A token associated with each download. Can be used to cancel a download @@ -249,10 +249,10 @@ typedef SDWebImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock; /** - SDWebImageDownloader is the built-in image loader conform to `SDWebImageLoader`. Which provide the HTTP/HTTPS/FTP download, or local file URL using NSURLSession. + SDWebImageDownloader is the built-in image loader conform to `SDImageLoader`. Which provide the HTTP/HTTPS/FTP download, or local file URL using NSURLSession. However, this downloader class itself also support customization for advanced users. You can specify `operationClass` in download config to custom download operation, See `SDWebImageDownloaderOperation`. - If you want to provide some image loader which beyond network or local file, consider to create your own custom class conform to `SDWebImageLoader`. + If you want to provide some image loader which beyond network or local file, consider to create your own custom class conform to `SDImageLoader`. */ -@interface SDWebImageDownloader (SDWebImageLoader) +@interface SDWebImageDownloader (SDImageLoader) @end diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index b107c2f7..71d96bd0 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -464,7 +464,7 @@ didReceiveResponse:(NSURLResponse *)response @end -@implementation SDWebImageDownloader (SDWebImageLoader) +@implementation SDWebImageDownloader (SDImageLoader) - (BOOL)canLoadWithURL:(NSURL *)url { if (!url) { @@ -474,7 +474,7 @@ didReceiveResponse:(NSURLResponse *)response return YES; } -- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDWebImageLoaderProgressBlock)progressBlock completed:(SDWebImageLoaderCompletedBlock)completedBlock { +- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDImageLoaderCompletedBlock)completedBlock { UIImage *cachedImage; if ([context valueForKey:SDWebImageContextLoaderCachedImage]) { cachedImage = [context valueForKey:SDWebImageContextLoaderCachedImage]; diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 7474f48f..a687367d 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -345,7 +345,7 @@ didReceiveResponse:(NSURLResponse *)response // progressive decode the image in coder queue dispatch_async(self.coderQueue, ^{ - UIImage *image = SDWebImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, finished, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); + UIImage *image = SDImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, finished, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); if (image) { // We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding. @@ -412,7 +412,7 @@ didReceiveResponse:(NSURLResponse *)response } else { // decode the image in coder queue dispatch_async(self.coderQueue, ^{ - UIImage *image = SDWebImageLoaderDecodeImageData(imageData, self.request.URL, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); + UIImage *image = SDImageLoaderDecodeImageData(imageData, self.request.URL, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); CGSize imageSize = image.size; if (imageSize.width == 0 || imageSize.height == 0) { [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorBadImageData userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}]]; diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 0b5d4061..ecc47a68 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -13,7 +13,7 @@ #import "SDImageTransformer.h" #import "SDWebImageCacheKeyFilter.h" #import "SDWebImageCacheSerializer.h" -#import "SDWebImageLoader.h" +#import "SDImageLoader.h" typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL); @@ -105,7 +105,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; /** * The image loader used by manager to load image. */ -@property (strong, nonatomic, readonly, nonnull) id imageLoader; +@property (strong, nonatomic, readonly, nonnull) id imageLoader; /** The image transformer for manager. It's used for image transform after the image load finished and store the transformed image to cache, see `SDImageTransformer`. @@ -164,7 +164,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; The default image loader for manager which is created with no arguments. Such as shared manager or init. Defaults to nil. Means using `SDWebImageDownloader.sharedDownloader` */ -@property (nonatomic, class, nullable) id defaultImageLoader; +@property (nonatomic, class, nullable) id defaultImageLoader; /** * Returns global shared manager instance. @@ -175,7 +175,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; * Allows to specify instance of cache and image loader used with image manager. * @return new instance of `SDWebImageManager` with specified cache and loader. */ -- (nonnull instancetype)initWithCache:(nonnull id)cache loader:(nonnull id)loader NS_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithCache:(nonnull id)cache loader:(nonnull id)loader NS_DESIGNATED_INITIALIZER; /** * Downloads the image at the given URL if not present in cache or return the cached version otherwise. diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 6d1f9d0d..970d89bb 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -17,7 +17,7 @@ #define UNLOCK(lock) dispatch_semaphore_signal(lock); static id _defaultImageCache; -static id _defaultImageLoader; +static id _defaultImageLoader; @interface SDWebImageCombinedOperation () @@ -31,7 +31,7 @@ static id _defaultImageLoader; @interface SDWebImageManager () @property (strong, nonatomic, readwrite, nonnull) SDImageCache *imageCache; -@property (strong, nonatomic, readwrite, nonnull) id imageLoader; +@property (strong, nonatomic, readwrite, nonnull) id imageLoader; @property (strong, nonatomic, nonnull) NSMutableSet *failedURLs; @property (strong, nonatomic, nonnull) dispatch_semaphore_t failedURLsLock; // a lock to keep the access to `failedURLs` thread-safe @property (strong, nonatomic, nonnull) NSMutableArray *runningOperations; @@ -52,12 +52,12 @@ static id _defaultImageLoader; _defaultImageCache = defaultImageCache; } -+ (id)defaultImageLoader { ++ (id)defaultImageLoader { return _defaultImageLoader; } -+ (void)setDefaultImageLoader:(id)defaultImageLoader { - if (defaultImageLoader && ![defaultImageLoader conformsToProtocol:@protocol(SDWebImageLoader)]) { ++ (void)setDefaultImageLoader:(id)defaultImageLoader { + if (defaultImageLoader && ![defaultImageLoader conformsToProtocol:@protocol(SDImageLoader)]) { return; } _defaultImageLoader = defaultImageLoader; @@ -77,14 +77,14 @@ static id _defaultImageLoader; if (!cache) { cache = [SDImageCache sharedImageCache]; } - id loader = [[self class] defaultImageLoader]; + id loader = [[self class] defaultImageLoader]; if (!loader) { loader = [SDWebImageDownloader sharedDownloader]; } return [self initWithCache:cache loader:loader]; } -- (nonnull instancetype)initWithCache:(nonnull id)cache loader:(nonnull id)loader { +- (nonnull instancetype)initWithCache:(nonnull id)cache loader:(nonnull id)loader { if ((self = [super init])) { _imageCache = cache; _imageLoader = loader; diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index 864ffb5f..4f9ba055 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -36,8 +36,8 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import -#import -#import +#import +#import #import #import #import From 4eb13bf2a12f7febf236b5c260f0c5faa13b9d53 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 17 May 2018 14:04:57 +0800 Subject: [PATCH 186/361] Remove the header dependency of SDWebImageManager of SDWebImageDownloader. Use SDImageLoaderProgressBlock instead of SDWebImageDownloadProgressBlock --- .../FLAnimatedImage/FLAnimatedImageView+WebCache.h | 2 +- .../FLAnimatedImage/FLAnimatedImageView+WebCache.m | 4 ++-- SDWebImage/MapKit/MKAnnotationView+WebCache.h | 4 ++-- SDWebImage/MapKit/MKAnnotationView+WebCache.m | 4 ++-- SDWebImage/NSButton+WebCache.h | 8 ++++---- SDWebImage/NSButton+WebCache.m | 8 ++++---- SDWebImage/SDAnimatedImageView+WebCache.h | 4 ++-- SDWebImage/SDAnimatedImageView+WebCache.m | 4 ++-- SDWebImage/SDWebImageManager.h | 7 +++---- SDWebImage/SDWebImageManager.m | 11 +++++------ SDWebImage/UIButton+WebCache.h | 8 ++++---- SDWebImage/UIButton+WebCache.m | 8 ++++---- SDWebImage/UIImageView+HighlightedWebCache.h | 2 +- SDWebImage/UIImageView+HighlightedWebCache.m | 4 ++-- SDWebImage/UIImageView+WebCache.h | 4 ++-- SDWebImage/UIImageView+WebCache.m | 4 ++-- SDWebImage/UIView+WebCache.h | 2 +- SDWebImage/UIView+WebCache.m | 6 ++++-- 18 files changed, 47 insertions(+), 47 deletions(-) diff --git a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.h b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.h index f046f7a6..c3896efb 100644 --- a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.h +++ b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.h @@ -153,7 +153,7 @@ - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; @end diff --git a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m index 51833df0..203b9118 100644 --- a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m +++ b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m @@ -80,7 +80,7 @@ [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; } -- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDExternalCompletionBlock)completedBlock { +- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; } @@ -88,7 +88,7 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { dispatch_group_t group = dispatch_group_create(); SDWebImageMutableContext *mutableContext; diff --git a/SDWebImage/MapKit/MKAnnotationView+WebCache.h b/SDWebImage/MapKit/MKAnnotationView+WebCache.h index 7fec73d8..f8a87555 100644 --- a/SDWebImage/MapKit/MKAnnotationView+WebCache.h +++ b/SDWebImage/MapKit/MKAnnotationView+WebCache.h @@ -123,7 +123,7 @@ - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; /** @@ -147,7 +147,7 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; @end diff --git a/SDWebImage/MapKit/MKAnnotationView+WebCache.m b/SDWebImage/MapKit/MKAnnotationView+WebCache.m index c228249b..d72785ca 100644 --- a/SDWebImage/MapKit/MKAnnotationView+WebCache.m +++ b/SDWebImage/MapKit/MKAnnotationView+WebCache.m @@ -40,7 +40,7 @@ [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; } -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; } @@ -48,7 +48,7 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { __weak typeof(self)weakSelf = self; [self sd_internalSetImageWithURL:url diff --git a/SDWebImage/NSButton+WebCache.h b/SDWebImage/NSButton+WebCache.h index 0edb7a4b..1f854779 100644 --- a/SDWebImage/NSButton+WebCache.h +++ b/SDWebImage/NSButton+WebCache.h @@ -125,7 +125,7 @@ - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; /** @@ -149,7 +149,7 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; #pragma mark - Alternate Image @@ -263,7 +263,7 @@ - (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; /** @@ -287,7 +287,7 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; #pragma mark - Cancel diff --git a/SDWebImage/NSButton+WebCache.m b/SDWebImage/NSButton+WebCache.m index b8f5092b..30af27fb 100644 --- a/SDWebImage/NSButton+WebCache.m +++ b/SDWebImage/NSButton+WebCache.m @@ -44,7 +44,7 @@ static NSString * const SDAlternateImageOperationKey = @"NSButtonAlternateImageO [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; } -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; } @@ -52,7 +52,7 @@ static NSString * const SDAlternateImageOperationKey = @"NSButtonAlternateImageO placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { self.sd_currentImageURL = url; [self sd_internalSetImageWithURL:url @@ -94,7 +94,7 @@ static NSString * const SDAlternateImageOperationKey = @"NSButtonAlternateImageO [self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; } -- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; } @@ -102,7 +102,7 @@ static NSString * const SDAlternateImageOperationKey = @"NSButtonAlternateImageO placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { self.sd_currentAlternateImageURL = url; diff --git a/SDWebImage/SDAnimatedImageView+WebCache.h b/SDWebImage/SDAnimatedImageView+WebCache.h index 6a1b0fc1..91b29eb6 100644 --- a/SDWebImage/SDAnimatedImageView+WebCache.h +++ b/SDWebImage/SDAnimatedImageView+WebCache.h @@ -118,7 +118,7 @@ - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; /** @@ -142,7 +142,7 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; @end diff --git a/SDWebImage/SDAnimatedImageView+WebCache.m b/SDWebImage/SDAnimatedImageView+WebCache.m index fa9407bb..bc8c08d8 100644 --- a/SDWebImage/SDAnimatedImageView+WebCache.m +++ b/SDWebImage/SDAnimatedImageView+WebCache.m @@ -39,7 +39,7 @@ [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; } -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; } @@ -47,7 +47,7 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { Class animatedImageClass = [SDAnimatedImage class]; SDWebImageMutableContext *mutableContext; diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index ecc47a68..40b78468 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -9,11 +9,10 @@ #import "SDWebImageCompat.h" #import "SDWebImageOperation.h" #import "SDImageCacheDefine.h" -#import "SDWebImageDownloader.h" +#import "SDImageLoader.h" #import "SDImageTransformer.h" #import "SDWebImageCacheKeyFilter.h" #import "SDWebImageCacheSerializer.h" -#import "SDImageLoader.h" typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL); @@ -204,7 +203,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; */ - (nullable SDWebImageCombinedOperation *)loadImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nonnull SDInternalCompletionBlock)completedBlock; /** @@ -222,7 +221,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; - (nullable SDWebImageCombinedOperation *)loadImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nonnull SDInternalCompletionBlock)completedBlock; /** diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 970d89bb..e4dd08b8 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -8,9 +8,8 @@ #import "SDWebImageManager.h" #import "SDImageCache.h" -#import "NSImage+Compatibility.h" +#import "SDWebImageDownloader.h" #import "UIImage+WebCache.h" -#import "SDAnimatedImage.h" #import "SDWebImageError.h" #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); @@ -116,14 +115,14 @@ static id _defaultImageLoader; return SDScaledImageForKey(key, image); } -- (SDWebImageCombinedOperation *)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDInternalCompletionBlock)completedBlock { +- (SDWebImageCombinedOperation *)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDInternalCompletionBlock)completedBlock { return [self loadImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock]; } - (SDWebImageCombinedOperation *)loadImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nonnull SDInternalCompletionBlock)completedBlock { // Invoking this method without a completedBlock is pointless NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead"); @@ -188,7 +187,7 @@ static id _defaultImageLoader; url:(nullable NSURL *)url options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDInternalCompletionBlock)completedBlock { // Check whether we should query cache BOOL shouldQueryCache = (options & SDWebImageFromLoaderOnly) == 0; @@ -218,7 +217,7 @@ static id _defaultImageLoader; cachedImage:(nullable UIImage *)cachedImage cachedData:(nullable NSData *)cachedData cacheType:(SDImageCacheType)cacheType - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDInternalCompletionBlock)completedBlock { // Check whether we should download image from network BOOL shouldDownload = (options & SDWebImageFromCacheOnly) == 0; diff --git a/SDWebImage/UIButton+WebCache.h b/SDWebImage/UIButton+WebCache.h index 0dea5b7a..b10e3097 100644 --- a/SDWebImage/UIButton+WebCache.h +++ b/SDWebImage/UIButton+WebCache.h @@ -149,7 +149,7 @@ forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; /** @@ -175,7 +175,7 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; #pragma mark - Background Image @@ -308,7 +308,7 @@ forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; /** @@ -333,7 +333,7 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; #pragma mark - Cancel diff --git a/SDWebImage/UIButton+WebCache.m b/SDWebImage/UIButton+WebCache.m index 9df79587..9fd576af 100644 --- a/SDWebImage/UIButton+WebCache.m +++ b/SDWebImage/UIButton+WebCache.m @@ -76,7 +76,7 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:options progress:nil completed:completedBlock]; } -- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { +- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; } @@ -85,7 +85,7 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { if (!url) { [self.sd_imageURLStorage removeObjectForKey:imageURLKeyForState(state)]; @@ -156,7 +156,7 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 progress:nil completed:completedBlock]; } -- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 context:nil progress:progressBlock completed:completedBlock]; } @@ -165,7 +165,7 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { if (!url) { [self.sd_imageURLStorage removeObjectForKey:backgroundImageURLKeyForState(state)]; diff --git a/SDWebImage/UIImageView+HighlightedWebCache.h b/SDWebImage/UIImageView+HighlightedWebCache.h index c806e5f2..a29782ba 100644 --- a/SDWebImage/UIImageView+HighlightedWebCache.h +++ b/SDWebImage/UIImageView+HighlightedWebCache.h @@ -86,7 +86,7 @@ */ - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; @end diff --git a/SDWebImage/UIImageView+HighlightedWebCache.m b/SDWebImage/UIImageView+HighlightedWebCache.m index e4dd3a51..9cc34fb8 100644 --- a/SDWebImage/UIImageView+HighlightedWebCache.m +++ b/SDWebImage/UIImageView+HighlightedWebCache.m @@ -33,14 +33,14 @@ static NSString * const SDHighlightedImageOperationKey = @"UIImageViewImageOpera [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:completedBlock]; } -- (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDExternalCompletionBlock)completedBlock { +- (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDExternalCompletionBlock)completedBlock { [self sd_setHighlightedImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock]; } - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { __weak typeof(self)weakSelf = self; SDWebImageMutableContext *mutableContext; diff --git a/SDWebImage/UIImageView+WebCache.h b/SDWebImage/UIImageView+WebCache.h index 1347f18d..c732b21c 100644 --- a/SDWebImage/UIImageView+WebCache.h +++ b/SDWebImage/UIImageView+WebCache.h @@ -148,7 +148,7 @@ - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; /** @@ -172,7 +172,7 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; #if SD_UIKIT diff --git a/SDWebImage/UIImageView+WebCache.m b/SDWebImage/UIImageView+WebCache.m index 63c19239..9ad97aed 100644 --- a/SDWebImage/UIImageView+WebCache.m +++ b/SDWebImage/UIImageView+WebCache.m @@ -37,7 +37,7 @@ [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; } -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock]; } @@ -45,7 +45,7 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_internalSetImageWithURL:url placeholderImage:placeholder diff --git a/SDWebImage/UIView+WebCache.h b/SDWebImage/UIView+WebCache.h index d674d9a1..10a383d3 100644 --- a/SDWebImage/UIView+WebCache.h +++ b/SDWebImage/UIView+WebCache.h @@ -66,7 +66,7 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context setImageBlock:(nullable SDSetImageBlock)setImageBlock - progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDInternalCompletionBlock)completedBlock; /** diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index dfe1ae7b..b2b3f4c5 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -40,7 +40,9 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context - setImageBlock:(nullable SDSetImageBlock)setImageBlock progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDInternalCompletionBlock)completedBlock { + setImageBlock:(nullable SDSetImageBlock)setImageBlock + progress:(nullable SDImageLoaderProgressBlock)progressBlock + completed:(nullable SDInternalCompletionBlock)completedBlock { context = [context copy]; // copy to avoid mutable object NSString *validOperationKey = nil; if ([context valueForKey:SDWebImageContextSetImageOperationKey]) { @@ -90,7 +92,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; } __weak __typeof(self)wself = self; - SDWebImageDownloaderProgressBlock combinedProgressBlock = ^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { + SDImageLoaderProgressBlock combinedProgressBlock = ^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { __strong __typeof (wself) sself = wself; NSProgress *imageProgress = sself.sd_imageProgress; imageProgress.totalUnitCount = expectedSize; From 1343a65321b4c2353882d5eeb9c1a24f49f0972d Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 17 May 2018 14:16:15 +0800 Subject: [PATCH 187/361] Fix the test --- Tests/Tests/SDWebImageDownloaderTests.m | 2 +- Tests/Tests/SDWebImageTestLoader.h | 4 ++-- Tests/Tests/SDWebImageTestLoader.m | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index 1d2de6fa..e2cfe5d5 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -433,7 +433,7 @@ - (void)test31ThatLoadersManagerWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Loaders manager not works"]; NSURL *imageURL = [NSURL URLWithString:kTestJpegURL]; - [[SDWebImageLoadersManager sharedManager] loadImageWithURL:imageURL options:0 context:nil progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { + [[SDImageLoadersManager sharedManager] loadImageWithURL:imageURL options:0 context:nil progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { expect(targetURL).notTo.beNil(); } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { expect(error).to.beNil(); diff --git a/Tests/Tests/SDWebImageTestLoader.h b/Tests/Tests/SDWebImageTestLoader.h index 10250240..d6a3f5f9 100644 --- a/Tests/Tests/SDWebImageTestLoader.h +++ b/Tests/Tests/SDWebImageTestLoader.h @@ -8,9 +8,9 @@ */ #import -#import +#import // A really naive implementation of custom image loader using `NSURLSession` -@interface SDWebImageTestLoader : NSObject +@interface SDWebImageTestLoader : NSObject @end diff --git a/Tests/Tests/SDWebImageTestLoader.m b/Tests/Tests/SDWebImageTestLoader.m index 65165d73..c4da8e73 100644 --- a/Tests/Tests/SDWebImageTestLoader.m +++ b/Tests/Tests/SDWebImageTestLoader.m @@ -20,13 +20,13 @@ return YES; } -- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDWebImageLoaderProgressBlock)progressBlock completed:(SDWebImageLoaderCompletedBlock)completedBlock { +- (id)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDImageLoaderCompletedBlock)completedBlock { NSURLRequest *request = [NSURLRequest requestWithURL:url]; NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (data) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - UIImage *image = SDWebImageLoaderDecodeImageData(data, url, options, context); + UIImage *image = SDImageLoaderDecodeImageData(data, url, options, context); if (completedBlock) { completedBlock(image, data, nil, YES); } From e5bee68164b959e3b6fbe0176109a829685c4ee8 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 15 Jun 2018 23:13:59 +0800 Subject: [PATCH 188/361] Add the `SDWebImageContextStoreCacheType` context option to specify detailed cache when the image is downloaded by manager and will store to cache. This replace the previous `SDWebImageCacheMemoryOnly` option, which is not so accurate and lack of detail control for cache behavior. --- SDWebImage/SDWebImageDefine.h | 51 +++++++++++++++++----------------- SDWebImage/SDWebImageDefine.m | 1 + SDWebImage/SDWebImageManager.m | 4 +-- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index 6aa0e326..5296ed39 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -61,16 +61,11 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { */ SDWebImageLowPriority = 1 << 1, - /** - * This flag disables on-disk caching after the download finished, only cache in memory - */ - SDWebImageCacheMemoryOnly = 1 << 2, - /** * This flag enables progressive download, the image is displayed progressively during download as a browser would do. * By default, the image is only displayed once completely downloaded. */ - SDWebImageProgressiveLoad = 1 << 3, + SDWebImageProgressiveLoad = 1 << 2, /** * Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed. @@ -80,107 +75,107 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { * * Use this flag only if you can't make your URLs static with embedded cache busting parameter. */ - SDWebImageRefreshCached = 1 << 4, + SDWebImageRefreshCached = 1 << 3, /** * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for * extra time in background to let the request finish. If the background task expires the operation will be cancelled. */ - SDWebImageContinueInBackground = 1 << 5, + SDWebImageContinueInBackground = 1 << 4, /** * Handles cookies stored in NSHTTPCookieStore by setting * NSMutableURLRequest.HTTPShouldHandleCookies = YES; */ - SDWebImageHandleCookies = 1 << 6, + SDWebImageHandleCookies = 1 << 5, /** * Enable to allow untrusted SSL certificates. * Useful for testing purposes. Use with caution in production. */ - SDWebImageAllowInvalidSSLCertificates = 1 << 7, + SDWebImageAllowInvalidSSLCertificates = 1 << 6, /** * By default, images are loaded in the order in which they were queued. This flag moves them to * the front of the queue. */ - SDWebImageHighPriority = 1 << 8, + SDWebImageHighPriority = 1 << 7, /** * By default, placeholder images are loaded while the image is loading. This flag will delay the loading * of the placeholder image until after the image has finished loading. */ - SDWebImageDelayPlaceholder = 1 << 9, + SDWebImageDelayPlaceholder = 1 << 8, /** * We usually don't apply transform on animated images as most transformers could not manage animated images. * Use this flag to transform them anyway. */ - SDWebImageTransformAnimatedImage = 1 << 10, + SDWebImageTransformAnimatedImage = 1 << 9, /** * By default, image is added to the imageView after download. But in some cases, we want to * have the hand before setting the image (apply a filter or add it with cross-fade animation for instance) * Use this flag if you want to manually set the image in the completion when success */ - SDWebImageAvoidAutoSetImage = 1 << 11, + SDWebImageAvoidAutoSetImage = 1 << 10, /** * By default, images are decoded respecting their original size. On iOS, this flag will scale down the * images to a size compatible with the constrained memory of devices. * This flag take no effect if `SDWebImageAvoidDecodeImage` is set. And it will be ignored if `SDWebImageProgressiveLoad` is set. */ - SDWebImageScaleDownLargeImages = 1 << 12, + SDWebImageScaleDownLargeImages = 1 << 11, /** * By default, we do not query image data when the image is already cached in memory. This mask can force to query image data at the same time. However, this query is asynchronously unless you specify `SDWebImageQueryMemoryDataSync` */ - SDWebImageQueryMemoryData = 1 << 13, + SDWebImageQueryMemoryData = 1 << 12, /** * By default, when you only specify `SDWebImageQueryMemoryData`, we query the memory image data asynchronously. Combined this mask as well to query the memory image data synchronously. * @note Query data synchronously is not recommend, unless you want to ensure the image is loaded in the same runloop to avoid flashing during cell reusing. */ - SDWebImageQueryMemoryDataSync = 1 << 14, + SDWebImageQueryMemoryDataSync = 1 << 13, /** * By default, when the memory cache miss, we query the disk cache asynchronously. This mask can force to query disk cache (when memory cache miss) synchronously. * @note These 3 query options can be combined together. For the full list about these masks combination, see wiki page. * @note Query data synchronously is not recommend, unless you want to ensure the image is loaded in the same runloop to avoid flashing during cell reusing. */ - SDWebImageQueryDiskDataSync = 1 << 15, + SDWebImageQueryDiskDataSync = 1 << 14, /** * By default, when the cache missed, the image is load from the loader. This flag can prevent this to load from cache only. */ - SDWebImageFromCacheOnly = 1 << 16, + SDWebImageFromCacheOnly = 1 << 15, /** * By default, we query the cache before the image is load from the loader. This flag can prevent this to load from loader only. */ - SDWebImageFromLoaderOnly = 1 << 17, + SDWebImageFromLoaderOnly = 1 << 16, /** * By default, when you use `SDWebImageTransition` to do some view transition after the image load finished, this transition is only applied for image download from the network. This mask can force to apply view transition for memory and disk cache as well. */ - SDWebImageForceTransition = 1 << 18, + SDWebImageForceTransition = 1 << 17, /** * By default, we will decode the image in the background during cache query and download from the network. This can help to improve performance because when rendering image on the screen, it need to be firstly decoded. But this happen on the main queue by Core Animation. * However, this process may increase the memory usage as well. If you are experiencing a issue due to excessive memory consumption, This flag can prevent decode the image. */ - SDWebImageAvoidDecodeImage = 1 << 19, + SDWebImageAvoidDecodeImage = 1 << 18, /** * By default, we decode the animated image. This flag can force decode the first frame only and produece the static image. */ - SDWebImageDecodeFirstFrameOnly = 1 << 20, + SDWebImageDecodeFirstFrameOnly = 1 << 19, /** * By default, for `SDAnimatedImage`, we decode the animated image frame during rendering to reduce memory usage. However, you can specify to preload all frames into memory to reduce CPU usage when the animated image is shared by lots of imageViews. * This will actually trigger `preloadAllAnimatedImageFrames` in the background queue(Disk Cache & Download only). */ - SDWebImagePreloadAllFrames = 1 << 21 + SDWebImagePreloadAllFrames = 1 << 20 }; @@ -207,10 +202,16 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustom FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageTransformer; /** - A CGFloat value which specify the image scale factor. The number should be greater than or equal to 1.0. If not provide or the number is invalid, we will use the cache key to specify the scale factor. (NSNumber) + A CGFloat raw value which specify the image scale factor. The number should be greater than or equal to 1.0. If not provide or the number is invalid, we will use the cache key to specify the scale factor. (NSNumber) */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageScaleFactor; +/** + A SDImageCacheType raw value which specify the cache type when the image has just been downloaded and will be stored to the cache. Specify `SDImageCacheTypeNone` to disable cache storage; `SDImageCacheTypeDisk` to store in disk cache only; `SDImageCacheTypeMemory` to store in memory only. And `SDImageCacheTypeAll` to store in both memory cache and disk cache. + If not provide or the value is invalid, we will use `SDImageCacheTypeAll`. (NSNumber) + */ +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextStoreCacheType; + /** A Class object which the instance is a `UIImage/NSImage` subclass and adopt `SDAnimatedImage` protocol. We will call `initWithData:scale:` to create the instance (or `initWithAnimatedCoder:scale` when using progressive download) . If the instance create failed, fallback to normal `UIImage/NSImage`. This can be used to improve animated images rendering performance (especially memory usage on big animated images) with `SDAnimatedImageView` (Class). diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m index 21bc081a..ffb7e64c 100644 --- a/SDWebImage/SDWebImageDefine.m +++ b/SDWebImage/SDWebImageDefine.m @@ -121,6 +121,7 @@ SDWebImageContextOption const SDWebImageContextSetImageGroup = @"setImageGroup"; SDWebImageContextOption const SDWebImageContextCustomManager = @"customManager"; SDWebImageContextOption const SDWebImageContextImageTransformer = @"imageTransformer"; SDWebImageContextOption const SDWebImageContextImageScaleFactor = @"imageScaleFactor"; +SDWebImageContextOption const SDWebImageContextStoreCacheType = @"storeCacheType"; SDWebImageContextOption const SDWebImageContextAnimatedImageClass = @"animatedImageClass"; SDWebImageContextOption const SDWebImageContextDownloadRequestModifier = @"downloadRequestModifier"; SDWebImageContextOption const SDWebImageContextCacheKeyFilter = @"cacheKeyFilter"; diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index e4dd08b8..3253e8a1 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -280,8 +280,8 @@ static id _defaultImageLoader; } SDImageCacheType storeCacheType = SDImageCacheTypeAll; - if (options & SDWebImageCacheMemoryOnly) { - storeCacheType = SDImageCacheTypeMemory; + if ([context valueForKey:SDWebImageContextStoreCacheType]) { + storeCacheType = [[context valueForKey:SDWebImageContextStoreCacheType] unsignedIntegerValue]; } id cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter]; NSString *key = [self cacheKeyForURL:url cacheKeyFilter:cacheKeyFilter]; From a57e0f7e131b3a0d5dea4a93569c1820d398fc02 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 15 Jun 2018 22:55:35 +0800 Subject: [PATCH 189/361] fix that SDImageCache does not use transformed key to query cache when provide a transformer --- SDWebImage/SDImageCache.m | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 3ae01792..4cab242a 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -344,6 +344,13 @@ return nil; } + if ([context valueForKey:SDWebImageContextImageTransformer]) { + // grab the transformed disk image if transformer provided + id transformer = [context valueForKey:SDWebImageContextImageTransformer]; + NSString *transformerKey = [transformer transformerKey]; + key = SDTransformedKeyForKey(key, transformerKey); + } + // First check the in-memory cache... UIImage *image = [self imageFromMemoryCacheForKey:key]; BOOL shouldQueryMemoryOnly = (image && !(options & SDImageCacheQueryMemoryData)); @@ -376,18 +383,11 @@ diskImage = image; cacheType = SDImageCacheTypeMemory; } else if (diskData) { - NSString *cacheKey = key; - if ([context valueForKey:SDWebImageContextImageTransformer]) { - // grab the transformed disk image if transformer provided - id transformer = [context valueForKey:SDWebImageContextImageTransformer]; - NSString *transformerKey = [transformer transformerKey]; - cacheKey = SDTransformedKeyForKey(key, transformerKey); - } // decode image data only if in-memory cache missed - diskImage = [self diskImageForKey:cacheKey data:diskData options:options context:context]; + diskImage = [self diskImageForKey:key data:diskData options:options context:context]; if (diskImage && self.config.shouldCacheImagesInMemory) { NSUInteger cost = SDMemoryCacheCostForImage(diskImage); - [self.memCache setObject:diskImage forKey:cacheKey cost:cost]; + [self.memCache setObject:diskImage forKey:key cost:cost]; } } @@ -698,7 +698,9 @@ - (void)clearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock { switch (cacheType) { case SDImageCacheTypeNone: { - return; + if (completionBlock) { + completionBlock(); + } } break; case SDImageCacheTypeMemory: { From e533a3da8044eb890c32af6a8fa1d9afc78f8997 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 15 Jun 2018 23:52:18 +0800 Subject: [PATCH 190/361] Refactor the UIImage+MultiFormat and GIF/WebP category. Simplify the usage and remove the extra method which is not used so common. --- SDWebImage/UIImage+GIF.h | 14 +++----------- SDWebImage/UIImage+GIF.m | 9 ++------- SDWebImage/UIImage+MultiFormat.h | 20 ++++++++++++++++++++ SDWebImage/UIImage+MultiFormat.m | 12 ++++++++++-- SDWebImage/WebP/UIImage+WebP.h | 12 ++---------- SDWebImage/WebP/UIImage+WebP.m | 7 +------ Tests/Tests/SDCategoriesTests.m | 4 ++-- 7 files changed, 40 insertions(+), 38 deletions(-) diff --git a/SDWebImage/UIImage+GIF.h b/SDWebImage/UIImage+GIF.h index 1062a291..38b986be 100644 --- a/SDWebImage/UIImage+GIF.h +++ b/SDWebImage/UIImage+GIF.h @@ -9,24 +9,16 @@ #import "SDWebImageCompat.h" +// This category is just use as a convenience method. For more detail control, use methods in `UIImage+MultiFormat.h` or directlly use `SDImageCoder` @interface UIImage (GIF) /** Creates an animated UIImage from an NSData. - For Static GIF, will create an UIImage with `images` array set to nil. For Animated GIF, will create an UIImage with valid `images` array. + This will create animated image if the data is Animated GIF. And will create a static image is the data is Static GIF. @param data The GIF data @return The created image */ -+ (nullable UIImage *)sd_animatedGIFWithData:(nullable NSData *)data; - -/** - Creates an animated UIImage from an NSData. - - @param data The GIF data - @param firstFrameOnly Even if the image data is Animated GIF format, decode the first frame only - @return The created image - */ -+ (nullable UIImage *)sd_animatedGIFWithData:(nullable NSData *)data firstFrameOnly:(BOOL)firstFrameOnly; ++ (nullable UIImage *)sd_imageWithGIFData:(nullable NSData *)data; @end diff --git a/SDWebImage/UIImage+GIF.m b/SDWebImage/UIImage+GIF.m index d2672721..7158cf31 100644 --- a/SDWebImage/UIImage+GIF.m +++ b/SDWebImage/UIImage+GIF.m @@ -12,16 +12,11 @@ @implementation UIImage (GIF) -+ (nullable UIImage *)sd_animatedGIFWithData:(nullable NSData *)data { - return [self sd_animatedGIFWithData:data firstFrameOnly:NO]; -} - -+ (nullable UIImage *)sd_animatedGIFWithData:(nullable NSData *)data firstFrameOnly:(BOOL)firstFrameOnly { ++ (nullable UIImage *)sd_imageWithGIFData:(nullable NSData *)data { if (!data) { return nil; } - SDImageCoderOptions *options = @{SDImageCoderDecodeFirstFrameOnly : @(firstFrameOnly)}; - return [[SDImageGIFCoder sharedCoder] decodedImageWithData:data options:options]; + return [[SDImageGIFCoder sharedCoder] decodedImageWithData:data options:0]; } @end diff --git a/SDWebImage/UIImage+MultiFormat.h b/SDWebImage/UIImage+MultiFormat.h index ff4b9ee8..951d66a5 100644 --- a/SDWebImage/UIImage+MultiFormat.h +++ b/SDWebImage/UIImage+MultiFormat.h @@ -28,6 +28,16 @@ */ + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data scale:(CGFloat)scale; +/** + Create and decode a image with the specify image data and scale, allow specify animate/static control + + @param data The image data + @param scale The image scale factor. Should be greater than or equal to 1.0. + @param firstFrameOnly Even if the image data is animated image format, decode the first frame only as static image. + @return The created image + */ ++ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data scale:(CGFloat)scale firstFrameOnly:(BOOL)firstFrameOnly; + #pragma mark - Encode /** Encode the current image to the data, the image format is unspecified @@ -53,4 +63,14 @@ */ - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat compressionQuality:(double)compressionQuality; +/** + Encode the current image to data with the specify image format and compression quality, allow specify animate/static control + + @param imageFormat The specify image format + @param compressionQuality The quality of the resulting image data. Value between 0.0-1.0. Some coders may not support compression quality. + @param firstFrameOnly Even if the image is animated image, encode the first frame only as static image. + @return The encoded data. If can't encode, return nil + */ +- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat compressionQuality:(double)compressionQuality firstFrameOnly:(BOOL)firstFrameOnly; + @end diff --git a/SDWebImage/UIImage+MultiFormat.m b/SDWebImage/UIImage+MultiFormat.m index 0e59b18d..c70a3808 100644 --- a/SDWebImage/UIImage+MultiFormat.m +++ b/SDWebImage/UIImage+MultiFormat.m @@ -16,13 +16,17 @@ } + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data scale:(CGFloat)scale { + return [self sd_imageWithData:data scale:scale firstFrameOnly:NO]; +} + ++ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data scale:(CGFloat)scale firstFrameOnly:(BOOL)firstFrameOnly { if (!data) { return nil; } if (scale < 1) { scale = 1; } - SDImageCoderOptions *options = @{SDImageCoderDecodeScaleFactor : @(scale)}; + SDImageCoderOptions *options = @{SDImageCoderDecodeScaleFactor : @(scale), SDImageCoderDecodeFirstFrameOnly : @(firstFrameOnly)}; return [[SDImageCodersManager sharedManager] decodedImageWithData:data options:options]; } @@ -35,7 +39,11 @@ } - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat compressionQuality:(double)compressionQuality { - SDImageCoderOptions *options = @{SDImageCoderEncodeCompressionQuality : @(compressionQuality)}; + return [self sd_imageDataAsFormat:imageFormat compressionQuality:compressionQuality firstFrameOnly:NO]; +} + +- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat compressionQuality:(double)compressionQuality firstFrameOnly:(BOOL)firstFrameOnly { + SDImageCoderOptions *options = @{SDImageCoderEncodeCompressionQuality : @(compressionQuality), SDImageCoderEncodeFirstFrameOnly : @(firstFrameOnly)}; return [[SDImageCodersManager sharedManager] encodedDataWithImage:self format:imageFormat options:options]; } diff --git a/SDWebImage/WebP/UIImage+WebP.h b/SDWebImage/WebP/UIImage+WebP.h index 7f4f50d4..b799b53c 100644 --- a/SDWebImage/WebP/UIImage+WebP.h +++ b/SDWebImage/WebP/UIImage+WebP.h @@ -10,26 +10,18 @@ #import "SDWebImageCompat.h" +// This category is just use as a convenience method. For more detail control, use methods in `UIImage+MultiFormat.h` or directlly use `SDImageCoder` @interface UIImage (WebP) /** Create a image from the WebP data. - This may create animated image if the data is Animated WebP. + This will create animated image if the data is Animated WebP. And will create a static image is the data is Static WebP. @param data The WebP data @return The created image */ + (nullable UIImage *)sd_imageWithWebPData:(nullable NSData *)data; -/** - Create a image from the WebP data. - - @param data The WebP data - @param firstFrameOnly Even if the image data is Animated WebP format, decode the first frame only - @return The created image - */ -+ (nullable UIImage *)sd_imageWithWebPData:(nullable NSData *)data firstFrameOnly:(BOOL)firstFrameOnly; - @end #endif diff --git a/SDWebImage/WebP/UIImage+WebP.m b/SDWebImage/WebP/UIImage+WebP.m index 9fe69554..011b8ad2 100644 --- a/SDWebImage/WebP/UIImage+WebP.m +++ b/SDWebImage/WebP/UIImage+WebP.m @@ -14,15 +14,10 @@ @implementation UIImage (WebP) + (nullable UIImage *)sd_imageWithWebPData:(nullable NSData *)data { - return [self sd_imageWithWebPData:data firstFrameOnly:NO]; -} - -+ (nullable UIImage *)sd_imageWithWebPData:(nullable NSData *)data firstFrameOnly:(BOOL)firstFrameOnly { if (!data) { return nil; } - SDImageCoderOptions *options = @{SDImageCoderDecodeFirstFrameOnly : @(firstFrameOnly)}; - return [[SDImageWebPCoder sharedCoder] decodedImageWithData:data options:options]; + return [[SDImageWebPCoder sharedCoder] decodedImageWithData:data options:0]; } @end diff --git a/Tests/Tests/SDCategoriesTests.m b/Tests/Tests/SDCategoriesTests.m index c8429284..36996529 100644 --- a/Tests/Tests/SDCategoriesTests.m +++ b/Tests/Tests/SDCategoriesTests.m @@ -43,11 +43,11 @@ - (void)test03UIImageGIFCategory { // Test invalid image data - UIImage *image = [UIImage sd_animatedGIFWithData:nil]; + UIImage *image = [UIImage sd_imageWithGIFData:nil]; expect(image).to.beNil(); // Test valid image data NSData *data = [NSData dataWithContentsOfFile:[self testGIFPath]]; - image = [UIImage sd_animatedGIFWithData:data]; + image = [UIImage sd_imageWithGIFData:data]; expect(image).notTo.beNil(); } From e5716db4d0b91e28940e854d5274af74685bf4f5 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 23 Jun 2018 15:04:12 +0800 Subject: [PATCH 191/361] Add one convenient method to pass context arg without completed block for all View Category --- SDWebImage/MapKit/MKAnnotationView+WebCache.h | 18 ++++- SDWebImage/MapKit/MKAnnotationView+WebCache.m | 6 +- SDWebImage/NSButton+WebCache.h | 32 ++++++++- SDWebImage/NSButton+WebCache.m | 8 +++ SDWebImage/SDAnimatedImageView+WebCache.h | 17 ++++- SDWebImage/SDAnimatedImageView+WebCache.m | 4 ++ SDWebImage/UIButton+WebCache.h | 66 ++++++++++++++----- SDWebImage/UIButton+WebCache.m | 12 +++- SDWebImage/UIImageView+HighlightedWebCache.h | 35 ++++++++++ SDWebImage/UIImageView+HighlightedWebCache.m | 6 +- SDWebImage/UIImageView+WebCache.h | 17 ++++- SDWebImage/UIImageView+WebCache.m | 4 ++ 12 files changed, 201 insertions(+), 24 deletions(-) diff --git a/SDWebImage/MapKit/MKAnnotationView+WebCache.h b/SDWebImage/MapKit/MKAnnotationView+WebCache.h index f8a87555..59346041 100644 --- a/SDWebImage/MapKit/MKAnnotationView+WebCache.h +++ b/SDWebImage/MapKit/MKAnnotationView+WebCache.h @@ -53,6 +53,22 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; +/** + * Set the imageView `image` with an `url`, placeholder, custom options and context. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + */ + +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context; + /** * Set the imageView `image` with an `url`. * @@ -127,7 +143,7 @@ completed:(nullable SDExternalCompletionBlock)completedBlock; /** - * Set the imageView `image` with an `url`, placeholder and custom options. + * Set the imageView `image` with an `url`, placeholder, custom options and context. * * The download is asynchronous and cached. * diff --git a/SDWebImage/MapKit/MKAnnotationView+WebCache.m b/SDWebImage/MapKit/MKAnnotationView+WebCache.m index d72785ca..15bb528d 100644 --- a/SDWebImage/MapKit/MKAnnotationView+WebCache.m +++ b/SDWebImage/MapKit/MKAnnotationView+WebCache.m @@ -25,7 +25,11 @@ } - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { - [self sd_setImageWithURL:url placeholderImage:placeholder options:options completed:nil]; + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:context progress:nil completed:nil]; } - (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { diff --git a/SDWebImage/NSButton+WebCache.h b/SDWebImage/NSButton+WebCache.h index 1f854779..85aa3fc7 100644 --- a/SDWebImage/NSButton+WebCache.h +++ b/SDWebImage/NSButton+WebCache.h @@ -55,6 +55,21 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; +/** + * Set the button `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context; + /** * Set the button `image` with an `url`. * @@ -193,6 +208,21 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; +/** + * Set the button `alternateImage` with an `url`, placeholder, custom options and context. + * + * The download is asynchronous and cached. + * + * @param url The url for the alternateImage. + * @param placeholder The alternateImage to be set initially, until the alternateImage request finishes. + * @param options The options to use when downloading the alternateImage. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + */ +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context; + /** * Set the button `alternateImage` with an `url`. * @@ -267,7 +297,7 @@ completed:(nullable SDExternalCompletionBlock)completedBlock; /** - * Set the button `alternateImage` with an `url`, placeholder and custom options. + * Set the button `alternateImage` with an `url`, placeholder, custom options and context. * * The download is asynchronous and cached. * diff --git a/SDWebImage/NSButton+WebCache.m b/SDWebImage/NSButton+WebCache.m index 30af27fb..e7f74844 100644 --- a/SDWebImage/NSButton+WebCache.m +++ b/SDWebImage/NSButton+WebCache.m @@ -32,6 +32,10 @@ static NSString * const SDAlternateImageOperationKey = @"NSButtonAlternateImageO [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; } +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:context progress:nil completed:nil]; +} + - (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; } @@ -82,6 +86,10 @@ static NSString * const SDAlternateImageOperationKey = @"NSButtonAlternateImageO [self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; } +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context { + [self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options context:context progress:nil completed:nil]; +} + - (void)sd_setAlternateImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setAlternateImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; } diff --git a/SDWebImage/SDAnimatedImageView+WebCache.h b/SDWebImage/SDAnimatedImageView+WebCache.h index 91b29eb6..ef677564 100644 --- a/SDWebImage/SDAnimatedImageView+WebCache.h +++ b/SDWebImage/SDAnimatedImageView+WebCache.h @@ -48,6 +48,21 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; +/** + * Set the imageView `image` with an `url`, placeholder, custom options and context. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context; + /** * Set the imageView `image` with an `url`. * @@ -122,7 +137,7 @@ completed:(nullable SDExternalCompletionBlock)completedBlock; /** - * Set the imageView `image` with an `url`, placeholder and custom options. + * Set the imageView `image` with an `url`, placeholder, custom options and context. * * The download is asynchronous and cached. * diff --git a/SDWebImage/SDAnimatedImageView+WebCache.m b/SDWebImage/SDAnimatedImageView+WebCache.m index bc8c08d8..beb56b2c 100644 --- a/SDWebImage/SDAnimatedImageView+WebCache.m +++ b/SDWebImage/SDAnimatedImageView+WebCache.m @@ -27,6 +27,10 @@ [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; } +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:context progress:nil completed:nil]; +} + - (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; } diff --git a/SDWebImage/UIButton+WebCache.h b/SDWebImage/UIButton+WebCache.h index b10e3097..8cb99de3 100644 --- a/SDWebImage/UIButton+WebCache.h +++ b/SDWebImage/UIButton+WebCache.h @@ -32,7 +32,7 @@ - (nullable NSURL *)sd_imageURLForState:(UIControlState)state; /** - * Set the imageView `image` with an `url`. + * Set the button `image` with an `url`. * * The download is asynchronous and cached. * @@ -43,7 +43,7 @@ forState:(UIControlState)state NS_REFINED_FOR_SWIFT; /** - * Set the imageView `image` with an `url` and a placeholder. + * Set the button `image` with an `url` and a placeholder. * * The download is asynchronous and cached. * @@ -57,7 +57,7 @@ placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT; /** - * Set the imageView `image` with an `url`, placeholder and custom options. + * Set the button `image` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * @@ -72,7 +72,24 @@ options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; /** - * Set the imageView `image` with an `url`. + * Set the button `image` with an `url`, placeholder, custom options and context. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context; + +/** + * Set the button `image` with an `url`. * * The download is asynchronous and cached. * @@ -89,7 +106,7 @@ completed:(nullable SDExternalCompletionBlock)completedBlock; /** - * Set the imageView `image` with an `url`, placeholder. + * Set the button `image` with an `url`, placeholder. * * The download is asynchronous and cached. * @@ -108,7 +125,7 @@ completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT; /** - * Set the imageView `image` with an `url`, placeholder and custom options. + * Set the button `image` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * @@ -129,7 +146,7 @@ completed:(nullable SDExternalCompletionBlock)completedBlock; /** - * Set the imageView `image` with an `url`, placeholder and custom options. + * Set the button `image` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * @@ -153,7 +170,7 @@ completed:(nullable SDExternalCompletionBlock)completedBlock; /** - * Set the imageView `image` with an `url`, placeholder and custom options. + * Set the button `image` with an `url`, placeholder, custom options and context. * * The download is asynchronous and cached. * @@ -193,7 +210,7 @@ - (nullable NSURL *)sd_backgroundImageURLForState:(UIControlState)state; /** - * Set the backgroundImageView `image` with an `url`. + * Set the button `backgroundImage` with an `url`. * * The download is asynchronous and cached. * @@ -204,7 +221,7 @@ forState:(UIControlState)state NS_REFINED_FOR_SWIFT; /** - * Set the backgroundImageView `image` with an `url` and a placeholder. + * Set the button `backgroundImage` with an `url` and a placeholder. * * The download is asynchronous and cached. * @@ -218,7 +235,7 @@ placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT; /** - * Set the backgroundImageView `image` with an `url`, placeholder and custom options. + * Set the button `backgroundImage` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * @@ -233,7 +250,24 @@ options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; /** - * Set the backgroundImageView `image` with an `url`. + * Set the button `backgroundImage` with an `url`, placeholder, custom options and context. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + */ +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context; + +/** + * Set the button `backgroundImage` with an `url`. * * The download is asynchronous and cached. * @@ -250,7 +284,7 @@ completed:(nullable SDExternalCompletionBlock)completedBlock; /** - * Set the backgroundImageView `image` with an `url`, placeholder. + * Set the button `backgroundImage` with an `url`, placeholder. * * The download is asynchronous and cached. * @@ -269,7 +303,7 @@ completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT; /** - * Set the backgroundImageView `image` with an `url`, placeholder and custom options. + * Set the button `backgroundImage` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * @@ -289,7 +323,7 @@ completed:(nullable SDExternalCompletionBlock)completedBlock; /** - * Set the backgroundImageView `image` with an `url`, placeholder and custom options. + * Set the button `backgroundImage` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * @@ -312,7 +346,7 @@ completed:(nullable SDExternalCompletionBlock)completedBlock; /** - * Set the backgroundImageView `image` with an `url`, placeholder and custom options. + * Set the button `backgroundImage` with an `url`, placeholder, custom options and context. * * The download is asynchronous and cached. * diff --git a/SDWebImage/UIButton+WebCache.m b/SDWebImage/UIButton+WebCache.m index 9fd576af..8da05c77 100644 --- a/SDWebImage/UIButton+WebCache.m +++ b/SDWebImage/UIButton+WebCache.m @@ -61,7 +61,11 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat } - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { - [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil]; + [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:options progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context { + [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:options context:context progress:nil completed:nil]; } - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state completed:(nullable SDExternalCompletionBlock)completedBlock { @@ -141,7 +145,11 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat } - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { - [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil]; + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:options progress:nil completed:nil]; +} + +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:options context:context progress:nil completed:nil]; } - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state completed:(nullable SDExternalCompletionBlock)completedBlock { diff --git a/SDWebImage/UIImageView+HighlightedWebCache.h b/SDWebImage/UIImageView+HighlightedWebCache.h index a29782ba..6cd3ba61 100644 --- a/SDWebImage/UIImageView+HighlightedWebCache.h +++ b/SDWebImage/UIImageView+HighlightedWebCache.h @@ -37,6 +37,19 @@ - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; +/** + * Set the imageView `highlightedImage` with an `url`, custom options and context. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + */ +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context; + /** * Set the imageView `highlightedImage` with an `url`. * @@ -89,6 +102,28 @@ progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; +/** + * Set the imageView `highlightedImage` with an `url`, custom options and context. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + progress:(nullable SDImageLoaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + @end #endif diff --git a/SDWebImage/UIImageView+HighlightedWebCache.m b/SDWebImage/UIImageView+HighlightedWebCache.m index 9cc34fb8..a8803aa3 100644 --- a/SDWebImage/UIImageView+HighlightedWebCache.m +++ b/SDWebImage/UIImageView+HighlightedWebCache.m @@ -25,6 +25,10 @@ static NSString * const SDHighlightedImageOperationKey = @"UIImageViewImageOpera [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:nil]; } +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context { + [self sd_setHighlightedImageWithURL:url options:options context:context progress:nil completed:nil]; +} + - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:completedBlock]; } @@ -33,7 +37,7 @@ static NSString * const SDHighlightedImageOperationKey = @"UIImageViewImageOpera [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:completedBlock]; } -- (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDExternalCompletionBlock)completedBlock { +- (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setHighlightedImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock]; } diff --git a/SDWebImage/UIImageView+WebCache.h b/SDWebImage/UIImageView+WebCache.h index c732b21c..21df976a 100644 --- a/SDWebImage/UIImageView+WebCache.h +++ b/SDWebImage/UIImageView+WebCache.h @@ -78,6 +78,21 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; +/** + * Set the imageView `image` with an `url`, placeholder, custom options and context. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context; + /** * Set the imageView `image` with an `url`. * @@ -152,7 +167,7 @@ completed:(nullable SDExternalCompletionBlock)completedBlock; /** - * Set the imageView `image` with an `url`, placeholder and custom options. + * Set the imageView `image` with an `url`, placeholder, custom options and context. * * The download is asynchronous and cached. * diff --git a/SDWebImage/UIImageView+WebCache.m b/SDWebImage/UIImageView+WebCache.m index 9ad97aed..5d62e185 100644 --- a/SDWebImage/UIImageView+WebCache.m +++ b/SDWebImage/UIImageView+WebCache.m @@ -25,6 +25,10 @@ [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; } +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options context:context progress:nil completed:nil]; +} + - (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; } From 4dbb15712b820e918206f8eeaf0a830894b404ca Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 23 Jun 2018 23:06:48 +0800 Subject: [PATCH 192/361] Fix that UIImage+Transform on macOS to use BGRA8888 instead of ARGB8888, as Apple's doc --- SDWebImage/UIImage+Transform.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 323d4f44..5309bf72 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -14,14 +14,14 @@ #endif #if SD_MAC -static CGContextRef SDCGContextCreateARGBBitmapContext(CGSize size, BOOL opaque, CGFloat scale) { +static CGContextRef SDCGContextCreateBitmapContext(CGSize size, BOOL opaque, CGFloat scale) { size_t width = ceil(size.width * scale); size_t height = ceil(size.height * scale); if (width < 1 || height < 1) return NULL; - //pre-multiplied ARGB, 8-bits per component + //pre-multiplied BGRA, 8-bits per component, as Apple's doc CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); - CGImageAlphaInfo alphaInfo = (opaque ? kCGImageAlphaNoneSkipFirst : kCGImageAlphaPremultipliedFirst); + CGImageAlphaInfo alphaInfo = kCGBitmapByteOrder32Host | (opaque ? kCGImageAlphaNoneSkipFirst : kCGImageAlphaPremultipliedFirst); CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, space, kCGBitmapByteOrderDefault | alphaInfo); CGColorSpaceRelease(space); if (!context) { @@ -41,7 +41,7 @@ static void SDGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGF #if SD_UIKIT || SD_WATCH UIGraphicsBeginImageContextWithOptions(size, opaque, scale); #else - CGContextRef context = SDCGContextCreateARGBBitmapContext(size, opaque, scale); + CGContextRef context = SDCGContextCreateBitmapContext(size, opaque, scale); if (!context) { return; } From a82a4e15b2f49b3d5488fc4f871c5324743774f1 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 25 Jun 2018 13:52:46 +0800 Subject: [PATCH 193/361] Renaming UIImage+WebCache to the correct naming UIImage+Metadata, make clear of the category usage --- SDWebImage.xcodeproj/project.pbxproj | 56 +++++++++---------- SDWebImage/NSImage+Compatibility.h | 2 +- SDWebImage/SDAnimatedImage.m | 1 - SDWebImage/SDAnimatedImageView.h | 2 +- SDWebImage/SDAnimatedImageView.m | 2 +- SDWebImage/SDImageAPNGCoder.m | 2 +- SDWebImage/SDImageCache.m | 1 - SDWebImage/SDImageCacheDefine.m | 2 +- SDWebImage/SDImageCoderHelper.m | 2 +- SDWebImage/SDImageCodersManager.m | 2 - SDWebImage/SDImageFrame.h | 2 +- SDWebImage/SDImageGIFCoder.m | 2 +- SDWebImage/SDImageLoader.m | 2 +- SDWebImage/SDWebImageDefine.h | 4 +- SDWebImage/SDWebImageDefine.m | 2 +- SDWebImage/SDWebImageManager.m | 2 +- ...{UIImage+WebCache.h => UIImage+Metadata.h} | 2 +- ...{UIImage+WebCache.m => UIImage+Metadata.m} | 6 +- SDWebImage/UIImage+Transform.m | 28 ++++++---- SDWebImage/WebP/SDImageWebPCoder.m | 2 +- WebImage/SDWebImage.h | 2 +- 21 files changed, 63 insertions(+), 63 deletions(-) rename SDWebImage/{UIImage+WebCache.h => UIImage+Metadata.h} (97%) rename SDWebImage/{UIImage+WebCache.m => UIImage+Metadata.m} (97%) diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 5e5b8210..b87f9506 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -470,18 +470,18 @@ 3290FA0D1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; 3290FA0E1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; 3290FA0F1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; }; - 329A18591FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 329A185A1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 329A185B1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 329A185C1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 329A185D1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 329A185E1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 329A185F1FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; - 329A18601FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; - 329A18611FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; - 329A18621FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; - 329A18631FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; - 329A18641FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */; }; + 329A18591FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 329A185A1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 329A185B1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 329A185C1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 329A185D1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 329A185E1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 329A185F1FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; + 329A18601FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; + 329A18611FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; + 329A18621FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; + 329A18631FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; + 329A18641FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; }; 32B9B537206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32B9B538206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1616,8 +1616,8 @@ 328BB6C02082581100760D6C /* SDMemoryCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDMemoryCache.m; sourceTree = ""; }; 3290FA021FA478AF0047D20C /* SDImageFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageFrame.h; sourceTree = ""; }; 3290FA031FA478AF0047D20C /* SDImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageFrame.m; sourceTree = ""; }; - 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImage+WebCache.h"; path = "SDWebImage/UIImage+WebCache.h"; sourceTree = ""; }; - 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImage+WebCache.m"; path = "SDWebImage/UIImage+WebCache.m"; sourceTree = ""; }; + 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Metadata.h"; sourceTree = ""; }; + 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Metadata.m"; sourceTree = ""; }; 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderConfig.h; sourceTree = ""; }; 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderConfig.m; sourceTree = ""; }; 32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageIndicator.h; sourceTree = ""; }; @@ -2005,8 +2005,6 @@ 4369C2851D9811BB007E863A /* WebCache Categories */ = { isa = PBXGroup; children = ( - 329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */, - 329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */, 321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */, 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */, 53922D93148C56230056699D /* UIButton+WebCache.h */, @@ -2141,6 +2139,8 @@ 5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */, A18A6CC5172DC28500419892 /* UIImage+GIF.h */, A18A6CC6172DC28500419892 /* UIImage+GIF.m */, + 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */, + 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */, 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */, 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */, 321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */, @@ -2400,7 +2400,7 @@ 80377C4A1F2F666300F89830 /* bit_writer_utils.h in Headers */, 321B37902083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, 323F8BE71F38EF770092B609 /* vp8li_enc.h in Headers */, - 329A185C1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, + 329A185C1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, 4369C27A1D9807EC007E863A /* UIView+WebCache.h in Headers */, 32F21B5420788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 80377DCC1F2F66A700F89830 /* lossless_common.h in Headers */, @@ -2516,7 +2516,7 @@ 80377D501F2F66A700F89830 /* mips_macro.h in Headers */, 80377C291F2F666300F89830 /* thread_utils.h in Headers */, 4314D16D1D0E0E3B004B36C9 /* SDImageCache.h in Headers */, - 329A185A1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, + 329A185A1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, 4314D16F1D0E0E3B004B36C9 /* NSData+ImageContentType.h in Headers */, 80377C121F2F666300F89830 /* bit_reader_inl_utils.h in Headers */, 4314D1701D0E0E3B004B36C9 /* mux.h in Headers */, @@ -2599,7 +2599,7 @@ 80377C601F2F666400F89830 /* bit_reader_inl_utils.h in Headers */, 32FDE89920888726008D7530 /* UIImage+WebP.h in Headers */, 321B37852083290E00C0EA77 /* SDImageLoader.h in Headers */, - 329A185D1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, + 329A185D1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, 431BB6DC1D06D2C1006A3455 /* UIButton+WebCache.h in Headers */, 431BB6E11D06D2C1006A3455 /* SDWebImage.h in Headers */, 80377E311F2F66A800F89830 /* yuv.h in Headers */, @@ -2724,7 +2724,7 @@ 80377E481F2F66A800F89830 /* dsp.h in Headers */, 323F8BE91F38EF770092B609 /* vp8li_enc.h in Headers */, 3248477A201775F600AF9E5A /* SDAnimatedImage.h in Headers */, - 329A185E1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, + 329A185E1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, 320224BB203979BA00E9F285 /* SDAnimatedImageRep.h in Headers */, 328BB6C62082581100760D6C /* SDDiskCache.h in Headers */, 32FDE89420888726008D7530 /* SDImageWebPCoder.h in Headers */, @@ -2797,7 +2797,7 @@ 321B378F2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */, 431739541CDFC8B70008FEB9 /* types.h in Headers */, 323F8BE61F38EF770092B609 /* vp8li_enc.h in Headers */, - 329A185B1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, + 329A185B1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, 4369C2791D9807EC007E863A /* UIView+WebCache.h in Headers */, 32F21B5320788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */, 80377D871F2F66A700F89830 /* lossless_common.h in Headers */, @@ -2915,7 +2915,7 @@ 321E60941F38E8ED00405457 /* SDImageIOCoder.h in Headers */, 431738BD1CDFC2660008FEB9 /* decode.h in Headers */, 80377D0B1F2F66A100F89830 /* mips_macro.h in Headers */, - 329A18591FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */, + 329A18591FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */, 32D122302080B2EB003685A3 /* SDImageCachesManager.h in Headers */, 5376131A155AD0D5005750A4 /* SDWebImageDownloader.h in Headers */, 328BB6CD2082581100760D6C /* SDMemoryCache.h in Headers */, @@ -3355,7 +3355,7 @@ 00733A5E1BC4880000A5A117 /* UIImage+MultiFormat.m in Sources */, 80377DD01F2F66A700F89830 /* lossless_enc_neon.c in Sources */, 80377DE21F2F66A700F89830 /* rescaler.c in Sources */, - 329A18621FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, + 329A18621FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, 80377DAD1F2F66A700F89830 /* argb_mips_dsp_r2.c in Sources */, 328BB6B32081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, 00733A601BC4880000A5A117 /* UIImageView+HighlightedWebCache.m in Sources */, @@ -3380,7 +3380,7 @@ 80377EA01F2F66D400F89830 /* vp8_dec.c in Sources */, 80377EA31F2F66D400F89830 /* vp8l_dec.c in Sources */, 80377E9D1F2F66D400F89830 /* io_dec.c in Sources */, - 329A18601FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, + 329A18601FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, 80377D541F2F66A700F89830 /* rescaler_mips32.c in Sources */, 80377D331F2F66A700F89830 /* dec.c in Sources */, 32EB6D92206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, @@ -3546,7 +3546,7 @@ 80377ED01F2F66D500F89830 /* vp8_dec.c in Sources */, 80377ED31F2F66D500F89830 /* vp8l_dec.c in Sources */, 80377ECD1F2F66D500F89830 /* io_dec.c in Sources */, - 329A18631FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, + 329A18631FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, 80377E231F2F66A800F89830 /* rescaler_mips32.c in Sources */, 80377E021F2F66A800F89830 /* dec.c in Sources */, 32EB6D8F206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */, @@ -3736,7 +3736,7 @@ 32CF1C121FA496B000004BD1 /* SDImageCoderHelper.m in Sources */, 32B9B542206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, 80377E521F2F66A800F89830 /* filters_msa.c in Sources */, - 329A18641FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, + 329A18641FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, 80377C821F2F666400F89830 /* filters_utils.c in Sources */, 324DF4BF200A14DC008A84CC /* SDWebImageDefine.m in Sources */, 4397D28C1D0DDD8C00BB2784 /* UIImageView+WebCache.m in Sources */, @@ -4025,7 +4025,7 @@ 43CE75801CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */, 4369C2801D9807EC007E863A /* UIView+WebCache.m in Sources */, 80377D8B1F2F66A700F89830 /* lossless_enc_neon.c in Sources */, - 329A18611FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, + 329A18611FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, 80377D9D1F2F66A700F89830 /* rescaler.c in Sources */, 328BB6B22081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, 80377D681F2F66A700F89830 /* argb_mips_dsp_r2.c in Sources */, @@ -4195,7 +4195,7 @@ 43CE757F1CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */, 4369C27E1D9807EC007E863A /* UIView+WebCache.m in Sources */, 80377D011F2F66A100F89830 /* lossless_enc_neon.c in Sources */, - 329A185F1FFF5DFD008C9A2F /* UIImage+WebCache.m in Sources */, + 329A185F1FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */, 80377D131F2F66A100F89830 /* rescaler.c in Sources */, 328BB6B02081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */, 80377CDE1F2F66A100F89830 /* argb_mips_dsp_r2.c in Sources */, diff --git a/SDWebImage/NSImage+Compatibility.h b/SDWebImage/NSImage+Compatibility.h index d41c1db8..80020258 100644 --- a/SDWebImage/NSImage+Compatibility.h +++ b/SDWebImage/NSImage+Compatibility.h @@ -8,7 +8,7 @@ #import "SDWebImageCompat.h" -// This category is provided to easily write cross-platform(AppKit/UIKit) code. For common usage, see `UIImage+WebCache`. +// This category is provided to easily write cross-platform(AppKit/UIKit) code. For common usage, see `UIImage+Metadata.h`. #if SD_MAC diff --git a/SDWebImage/SDAnimatedImage.m b/SDWebImage/SDAnimatedImage.m index d0fdec14..d05a430c 100644 --- a/SDWebImage/SDAnimatedImage.m +++ b/SDWebImage/SDAnimatedImage.m @@ -8,7 +8,6 @@ #import "SDAnimatedImage.h" #import "NSImage+Compatibility.h" -#import "UIImage+WebCache.h" #import "SDImageCoder.h" #import "SDImageCodersManager.h" #import "SDImageFrame.h" diff --git a/SDWebImage/SDAnimatedImageView.h b/SDWebImage/SDAnimatedImageView.h index 34806cf2..db904ace 100644 --- a/SDWebImage/SDAnimatedImageView.h +++ b/SDWebImage/SDAnimatedImageView.h @@ -51,7 +51,7 @@ */ @property (nonatomic, assign) NSUInteger maxBufferSize; /** - Whehter or not to enable incremental image load for animated image. This is for the animated image which `sd_isIncremental` is YES (See `UIImage+WebCache.h`). If enable, animated image rendering will stop at the last frame available currently, and continue when another `setImage:` trigger, where the new animated image's `animatedImageData` should be updated from the previous one. If the `sd_isIncremental` is NO. The incremental image load stop. + Whehter or not to enable incremental image load for animated image. This is for the animated image which `sd_isIncremental` is YES (See `UIImage+Metadata.h`). If enable, animated image rendering will stop at the last frame available currently, and continue when another `setImage:` trigger, where the new animated image's `animatedImageData` should be updated from the previous one. If the `sd_isIncremental` is NO. The incremental image load stop. @note If you are confused about this description, open Chrome browser to view some large GIF images with low network speed to see the animation behavior. @note The best practice to use incremental load is using `initWithAnimatedCoder:scale` in `SDAnimatedImage` with animated coder which conform to `SDProgressiveImageCoder` as well. Then call incremental update and incremental decode method to produce the image. Default is YES. Set to NO to only render the static poster for incremental animated image. diff --git a/SDWebImage/SDAnimatedImageView.m b/SDWebImage/SDAnimatedImageView.m index 0bf6bdc4..a848cade 100644 --- a/SDWebImage/SDAnimatedImageView.m +++ b/SDWebImage/SDAnimatedImageView.m @@ -10,7 +10,7 @@ #if SD_UIKIT || SD_MAC -#import "UIImage+WebCache.h" +#import "UIImage+Metadata.h" #import "NSImage+Compatibility.h" #import #import diff --git a/SDWebImage/SDImageAPNGCoder.m b/SDWebImage/SDImageAPNGCoder.m index f9da324d..5dafa197 100644 --- a/SDWebImage/SDImageAPNGCoder.m +++ b/SDWebImage/SDImageAPNGCoder.m @@ -9,7 +9,7 @@ #import "SDImageAPNGCoder.h" #import #import "NSData+ImageContentType.h" -#import "UIImage+WebCache.h" +#import "UIImage+Metadata.h" #import "NSImage+Compatibility.h" #import "SDImageCoderHelper.h" #import "SDAnimatedImageRep.h" diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 4cab242a..5b3d4299 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -10,7 +10,6 @@ #import "SDMemoryCache.h" #import "SDDiskCache.h" #import "NSImage+Compatibility.h" -#import "UIImage+WebCache.h" #import "SDImageCodersManager.h" #import "SDImageTransformer.h" #import "SDImageCoderHelper.h" diff --git a/SDWebImage/SDImageCacheDefine.m b/SDWebImage/SDImageCacheDefine.m index 28fd1f48..c6b7cc5a 100644 --- a/SDWebImage/SDImageCacheDefine.m +++ b/SDWebImage/SDImageCacheDefine.m @@ -10,7 +10,7 @@ #import "SDImageCodersManager.h" #import "SDImageCoderHelper.h" #import "SDAnimatedImage.h" -#import "UIImage+WebCache.h" +#import "UIImage+Metadata.h" UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context) { UIImage *image; diff --git a/SDWebImage/SDImageCoderHelper.m b/SDWebImage/SDImageCoderHelper.m index 0f2faee1..6aff85df 100644 --- a/SDWebImage/SDImageCoderHelper.m +++ b/SDWebImage/SDImageCoderHelper.m @@ -245,7 +245,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over if (width == 0 || height == 0) return NULL; BOOL hasAlpha = [self CGImageContainsAlpha:cgImage]; // iOS prefer BGRA8888 (premultiplied) or BGRX8888 bitmapInfo for screen rendering, which is same as `UIGraphicsBeginImageContext()` or `- [CALayer drawInContext:]` - // Through you can use any supported bitmapInfo (see: https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html#//apple_ref/doc/uid/TP30001066-CH203-BCIBHHBB ) and let Core Graphics reorder it when you call `CGContextDrawImage` + // Though you can use any supported bitmapInfo (see: https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html#//apple_ref/doc/uid/TP30001066-CH203-BCIBHHBB ) and let Core Graphics reorder it when you call `CGContextDrawImage` // But since our build-in coders use this bitmapInfo, this can have a little performance benefit CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; diff --git a/SDWebImage/SDImageCodersManager.m b/SDWebImage/SDImageCodersManager.m index 33e1856f..83da2455 100644 --- a/SDWebImage/SDImageCodersManager.m +++ b/SDWebImage/SDImageCodersManager.m @@ -13,8 +13,6 @@ #ifdef SD_WEBP #import "SDImageWebPCoder.h" #endif -#import "NSImage+Compatibility.h" -#import "UIImage+WebCache.h" #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); #define UNLOCK(lock) dispatch_semaphore_signal(lock); diff --git a/SDWebImage/SDImageFrame.h b/SDWebImage/SDImageFrame.h index ae56f9d9..a1082b46 100644 --- a/SDWebImage/SDImageFrame.h +++ b/SDWebImage/SDImageFrame.h @@ -11,7 +11,7 @@ @interface SDImageFrame : NSObject -// This class is used for creating animated images via `animatedImageWithFrames` in `SDImageCoderHelper`. Attention if you need to specify animated images loop count, use `sd_imageLoopCount` property in `UIImage+WebCache.h`. +// This class is used for creating animated images via `animatedImageWithFrames` in `SDImageCoderHelper`. Attention if you need to specify animated images loop count, use `sd_imageLoopCount` property in `UIImage+Metadata.h`. /** The image of current frame. You should not set an animated image. diff --git a/SDWebImage/SDImageGIFCoder.m b/SDWebImage/SDImageGIFCoder.m index 2b9dca50..b5f68dd0 100644 --- a/SDWebImage/SDImageGIFCoder.m +++ b/SDWebImage/SDImageGIFCoder.m @@ -8,7 +8,7 @@ #import "SDImageGIFCoder.h" #import "NSImage+Compatibility.h" -#import "UIImage+WebCache.h" +#import "UIImage+Metadata.h" #import #import "NSData+ImageContentType.h" #import "SDImageCoderHelper.h" diff --git a/SDWebImage/SDImageLoader.m b/SDWebImage/SDImageLoader.m index cb7598a2..dbcf7f52 100644 --- a/SDWebImage/SDImageLoader.m +++ b/SDWebImage/SDImageLoader.m @@ -11,7 +11,7 @@ #import "SDImageCodersManager.h" #import "SDImageCoderHelper.h" #import "SDAnimatedImage.h" -#import "UIImage+WebCache.h" +#import "UIImage+Metadata.h" #import "objc/runtime.h" static void * SDImageLoaderProgressiveCoderKey = &SDImageLoaderProgressiveCoderKey; diff --git a/SDWebImage/SDWebImageDefine.h b/SDWebImage/SDWebImageDefine.h index 5296ed39..2bf37634 100644 --- a/SDWebImage/SDWebImageDefine.h +++ b/SDWebImage/SDWebImageDefine.h @@ -27,7 +27,7 @@ FOUNDATION_EXPORT CGFloat SDImageScaleFactorForKey(NSString * _Nullable key); /** Scale the image with the scale factor for the specify key. If no need to scale, return the original image. - This works for `UIImage`(UIKit) or `NSImage`(AppKit). And this function also preserve the associated value in `UIImage+WebCache`. + This works for `UIImage`(UIKit) or `NSImage`(AppKit). And this function also preserve the associated value in `UIImage+Metadata.h`. @note This is actually a convenience function, which firstlly call `SDImageScaleFactorForKey` and then call `SDScaledImageForScaleFactor`, kept for backward compatibility. @param key The image cache key @@ -38,7 +38,7 @@ FOUNDATION_EXPORT UIImage * _Nullable SDScaledImageForKey(NSString * _Nullable k /** Scale the image with the scale factor. If no need to scale, return the original image. - This works for `UIImage`(UIKit) or `NSImage`(AppKit). And this function also preserve the associated value in `UIImage+WebCache`. + This works for `UIImage`(UIKit) or `NSImage`(AppKit). And this function also preserve the associated value in `UIImage+Metadata.h`. @param scale The image scale factor @param image The image diff --git a/SDWebImage/SDWebImageDefine.m b/SDWebImage/SDWebImageDefine.m index ffb7e64c..2181d3c3 100644 --- a/SDWebImage/SDWebImageDefine.m +++ b/SDWebImage/SDWebImageDefine.m @@ -7,7 +7,7 @@ */ #import "SDWebImageDefine.h" -#import "UIImage+WebCache.h" +#import "UIImage+Metadata.h" #import "NSImage+Compatibility.h" #pragma mark - Image scale diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 3253e8a1..85f57d36 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -9,7 +9,7 @@ #import "SDWebImageManager.h" #import "SDImageCache.h" #import "SDWebImageDownloader.h" -#import "UIImage+WebCache.h" +#import "UIImage+Metadata.h" #import "SDWebImageError.h" #define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); diff --git a/SDWebImage/UIImage+WebCache.h b/SDWebImage/UIImage+Metadata.h similarity index 97% rename from SDWebImage/UIImage+WebCache.h rename to SDWebImage/UIImage+Metadata.h index b53b17bb..08d5b59c 100644 --- a/SDWebImage/UIImage+WebCache.h +++ b/SDWebImage/UIImage+Metadata.h @@ -8,7 +8,7 @@ #import "SDWebImageCompat.h" -@interface UIImage (WebCache) +@interface UIImage (Metadata) /** * UIKit: diff --git a/SDWebImage/UIImage+WebCache.m b/SDWebImage/UIImage+Metadata.m similarity index 97% rename from SDWebImage/UIImage+WebCache.m rename to SDWebImage/UIImage+Metadata.m index 412b6e7f..1a42077d 100644 --- a/SDWebImage/UIImage+WebCache.m +++ b/SDWebImage/UIImage+Metadata.m @@ -6,13 +6,13 @@ * file that was distributed with this source code. */ -#import "UIImage+WebCache.h" +#import "UIImage+Metadata.h" #import "NSImage+Compatibility.h" #import "objc/runtime.h" #if SD_UIKIT || SD_WATCH -@implementation UIImage (WebCache) +@implementation UIImage (Metadata) - (NSUInteger)sd_imageLoopCount { NSUInteger imageLoopCount = 0; @@ -47,7 +47,7 @@ #if SD_MAC -@implementation NSImage (WebCache) +@implementation NSImage (Metadata) - (NSUInteger)sd_imageLoopCount { NSUInteger imageLoopCount = 0; diff --git a/SDWebImage/UIImage+Transform.m b/SDWebImage/UIImage+Transform.m index 5309bf72..ff95ea45 100644 --- a/SDWebImage/UIImage+Transform.m +++ b/SDWebImage/UIImage+Transform.m @@ -11,15 +11,18 @@ #import #if SD_UIKIT || SD_MAC #import +#import "objc/runtime.h" #endif #if SD_MAC +static void *kNSGraphicsContextScaleFactorKey; + static CGContextRef SDCGContextCreateBitmapContext(CGSize size, BOOL opaque, CGFloat scale) { size_t width = ceil(size.width * scale); size_t height = ceil(size.height * scale); if (width < 1 || height < 1) return NULL; - //pre-multiplied BGRA, 8-bits per component, as Apple's doc + //pre-multiplied BGRA for non-opaque, BGRX for opaque, 8-bits per component, as Apple's doc CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); CGImageAlphaInfo alphaInfo = kCGBitmapByteOrder32Host | (opaque ? kCGImageAlphaNoneSkipFirst : kCGImageAlphaPremultipliedFirst); CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, space, kCGBitmapByteOrderDefault | alphaInfo); @@ -46,6 +49,7 @@ static void SDGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGF return; } NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithCGContext:context flipped:NO]; + objc_setAssociatedObject(graphicsContext, &kNSGraphicsContextScaleFactorKey, @(scale), OBJC_ASSOCIATION_RETAIN); CGContextRelease(context); [NSGraphicsContext saveGraphicsState]; NSGraphicsContext.currentContext = graphicsContext; @@ -72,22 +76,22 @@ static UIImage * SDGraphicsGetImageFromCurrentImageContext(void) { #if SD_UIKIT || SD_WATCH return UIGraphicsGetImageFromCurrentImageContext(); #else - CGContextRef context = SDGraphicsGetCurrentContext(); - if (!context) { + NSGraphicsContext *context = NSGraphicsContext.currentContext; + CGContextRef contextRef = context.CGContext; + if (!contextRef) { return nil; } - CGImageRef imageRef = CGBitmapContextCreateImage(context); + CGImageRef imageRef = CGBitmapContextCreateImage(contextRef); if (!imageRef) { return nil; } - CGAffineTransform transform = CGContextGetCTM(context); - CGFloat xs = transform.a; - CGFloat ys = transform.d; - CGFloat scale; - if (xs == ys && xs > 0) { - scale = xs; - } else { - // Protect if x/y axis scale factor not equal + CGFloat scale = 0; + NSNumber *scaleFactor = objc_getAssociatedObject(context, &kNSGraphicsContextScaleFactorKey); + if ([scaleFactor isKindOfClass:[NSNumber class]]) { + scale = scaleFactor.doubleValue; + } + if (!scale) { + // reset to the scale factor of the device’s main screen if scale is 0. scale = [NSScreen mainScreen].backingScaleFactor; } NSImage *image = [[NSImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp]; diff --git a/SDWebImage/WebP/SDImageWebPCoder.m b/SDWebImage/WebP/SDImageWebPCoder.m index 6de0b5ec..f2171a7c 100644 --- a/SDWebImage/WebP/SDImageWebPCoder.m +++ b/SDWebImage/WebP/SDImageWebPCoder.m @@ -11,7 +11,7 @@ #import "SDImageWebPCoder.h" #import "SDImageCoderHelper.h" #import "NSImage+Compatibility.h" -#import "UIImage+WebCache.h" +#import "UIImage+Metadata.h" #import "UIImage+ForceDecode.h" #if __has_include() && __has_include() && __has_include() && __has_include() #import diff --git a/WebImage/SDWebImage.h b/WebImage/SDWebImage.h index 4f9ba055..9a2d5771 100644 --- a/WebImage/SDWebImage.h +++ b/WebImage/SDWebImage.h @@ -41,7 +41,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[]; #import #import #import -#import +#import #import #import #import From 6674b9f711ff23d8cc3715fee0859922a09b7fd3 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Tue, 3 Jul 2018 21:18:02 +0800 Subject: [PATCH 194/361] Fix HTTP Header key field nullable --- SDWebImage/SDAnimatedImageView.h | 2 +- SDWebImage/SDWebImageDownloader.m | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/SDWebImage/SDAnimatedImageView.h b/SDWebImage/SDAnimatedImageView.h index db904ace..6eb071e9 100644 --- a/SDWebImage/SDAnimatedImageView.h +++ b/SDWebImage/SDAnimatedImageView.h @@ -61,7 +61,7 @@ You can specify a runloop mode to let it rendering. Default is NSRunLoopCommonModes on multi-core iOS device, NSDefaultRunLoopMode on single-core iOS device */ -@property (nonatomic, copy, nonnull) NSRunLoopMode runLoopMode NS_AVAILABLE_IOS(3_1); +@property (nonatomic, copy, nonnull) NSRunLoopMode runLoopMode; @end diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 71d96bd0..cc17dd89 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -133,6 +133,9 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; } - (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field { + if (!field) { + return; + } NSMutableDictionary *mutableHTTPHeaders = [self.HTTPHeaders mutableCopy]; if (value) { [mutableHTTPHeaders setObject:value forKey:field]; From d84e656d05198b025f8d74878929b952419c10e5 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 4 Jul 2018 12:22:33 +0800 Subject: [PATCH 195/361] Remove unnecessary copy --- SDWebImage/SDImageCacheConfig.m | 2 +- SDWebImage/SDWebImageDownloaderConfig.h | 2 +- SDWebImage/SDWebImageDownloaderConfig.m | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/SDWebImage/SDImageCacheConfig.m b/SDWebImage/SDImageCacheConfig.m index db4b194b..84123581 100644 --- a/SDWebImage/SDImageCacheConfig.m +++ b/SDWebImage/SDImageCacheConfig.m @@ -50,7 +50,7 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week config.maxCacheSize = self.maxCacheSize; config.maxMemoryCost = self.maxMemoryCost; config.maxMemoryCount = self.maxMemoryCount; - config.namespacePrefix = [self.namespacePrefix copyWithZone:zone]; + config.namespacePrefix = self.namespacePrefix; config.fileManager = self.fileManager; // NSFileManager does not conform to NSCopying, just pass the reference config.memoryCacheClass = self.memoryCacheClass; config.diskCacheClass = self.diskCacheClass; diff --git a/SDWebImage/SDWebImageDownloaderConfig.h b/SDWebImage/SDWebImageDownloaderConfig.h index ca41767b..1b5d833e 100644 --- a/SDWebImage/SDWebImageDownloaderConfig.h +++ b/SDWebImage/SDWebImageDownloaderConfig.h @@ -67,7 +67,7 @@ typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { * Set the default URL credential to be set for request operations. * Defaults to nil. */ -@property (nonatomic, strong, nullable) NSURLCredential *urlCredential; +@property (nonatomic, copy, nullable) NSURLCredential *urlCredential; /** * Set username using for HTTP Basic authentication. diff --git a/SDWebImage/SDWebImageDownloaderConfig.m b/SDWebImage/SDWebImageDownloaderConfig.m index 393d6e06..79e15c9d 100644 --- a/SDWebImage/SDWebImageDownloaderConfig.m +++ b/SDWebImage/SDWebImageDownloaderConfig.m @@ -37,9 +37,9 @@ static SDWebImageDownloaderConfig * _defaultDownloaderConfig; config.sessionConfiguration = [self.sessionConfiguration copyWithZone:zone]; config.operationClass = self.operationClass; config.executionOrder = self.executionOrder; - config.urlCredential = [self.urlCredential copyWithZone:zone]; - config.username = [self.username copyWithZone:zone]; - config.password = [self.password copyWithZone:zone]; + config.urlCredential = self.urlCredential; + config.username = self.username; + config.password = self.password; return config; } From c294bebec1d899f6f4607a1179c7d1ad3dae49fa Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 4 Jul 2018 14:57:20 +0800 Subject: [PATCH 196/361] update available macro --- SDWebImage/SDAnimatedImageView.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SDWebImage/SDAnimatedImageView.h b/SDWebImage/SDAnimatedImageView.h index 6eb071e9..e822c4ea 100644 --- a/SDWebImage/SDAnimatedImageView.h +++ b/SDWebImage/SDAnimatedImageView.h @@ -57,12 +57,14 @@ Default is YES. Set to NO to only render the static poster for incremental animated image. */ @property (nonatomic, assign) BOOL shouldIncrementalLoad; + +#if SD_UIKIT /** You can specify a runloop mode to let it rendering. Default is NSRunLoopCommonModes on multi-core iOS device, NSDefaultRunLoopMode on single-core iOS device */ @property (nonatomic, copy, nonnull) NSRunLoopMode runLoopMode; - +#endif @end #endif From 572a07416184c52d1a64b0926296fae07736a693 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 4 Jul 2018 15:19:12 +0800 Subject: [PATCH 197/361] Fix SDImageLoaderManager that only load image when loader can handle url --- SDWebImage/SDImageLoadersManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/SDImageLoadersManager.m b/SDWebImage/SDImageLoadersManager.m index 123113bf..c53e4247 100644 --- a/SDWebImage/SDImageLoadersManager.m +++ b/SDWebImage/SDImageLoadersManager.m @@ -88,7 +88,7 @@ NSArray> *loaders = self.loaders; UNLOCK(self.loadersLock); for (id loader in loaders.reverseObjectEnumerator) { - if ([loader respondsToSelector:@selector(loadImageWithURL:options:context:progress:completed:)]) { + if ([loader canLoadWithURL:url]) { return [loader loadImageWithURL:url options:options context:context progress:progressBlock completed:completedBlock]; } } From 6d295c2a830fd87c37329e1a055d89e3e57364c2 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 4 Jul 2018 15:49:39 +0800 Subject: [PATCH 198/361] Fix typo --- SDWebImage/SDWebImagePrefetcher.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/SDWebImagePrefetcher.h b/SDWebImage/SDWebImagePrefetcher.h index 2f81c417..5c3bb8c0 100644 --- a/SDWebImage/SDWebImagePrefetcher.h +++ b/SDWebImage/SDWebImagePrefetcher.h @@ -14,7 +14,7 @@ @interface SDWebImagePrefetchToken : NSObject /** - * Cancel the current prefeching. + * Cancel the current prefetching. */ - (void)cancel; From a2d65b61e15c893869ed2a52042cc9b2be650df5 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 5 Jul 2018 22:03:35 +0800 Subject: [PATCH 199/361] Fix race condition of SDWebImagePrefetcher's completion handler --- SDWebImage/SDWebImagePrefetcher.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index 0b2d9ef3..c4490cea 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -16,6 +16,7 @@ atomic_ulong _skippedCount; atomic_ulong _finishedCount; atomic_ulong _totalCount; + atomic_flag _isAllFinished; } @property (nonatomic, copy, readwrite) NSArray *urls; @@ -78,6 +79,7 @@ token->_skippedCount = 0; token->_finishedCount = 0; token->_totalCount = token.urls.count; + atomic_flag_clear(&(token->_isAllFinished)); token.operations = [NSPointerArray weakObjectsPointerArray]; token.progressBlock = progressBlock; token.completionBlock = completionBlock; @@ -105,8 +107,10 @@ if (atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed) + atomic_load_explicit(&(token->_skippedCount), memory_order_relaxed) >= atomic_load_explicit(&(token->_totalCount), memory_order_relaxed)) { // All finished - [sself callCompletionBlockForToken:token]; - [sself removeRunningToken:token]; + if (!atomic_flag_test_and_set_explicit(&(token->_isAllFinished), memory_order_relaxed)) { + [sself callCompletionBlockForToken:token]; + [sself removeRunningToken:token]; + } } }]; @synchronized (token) { From bb55b6eb728a0ea5d96e429a20451777cc6d49a6 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 5 Jul 2018 22:24:25 +0800 Subject: [PATCH 200/361] Fix typo --- SDWebImage/SDWebImageManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 40b78468..94e09420 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -18,7 +18,7 @@ typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _N typedef void(^SDInternalCompletionBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL); -// A combined operation representing the cache and loader operation. You can it to cancel the load process. +// A combined operation representing the cache and loader operation. You can use it to cancel the load process. @interface SDWebImageCombinedOperation : NSObject /** From dd6e4a1d2e3cae2ed6e089a02a3bfae9449fe8fa Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 4 Jul 2018 13:32:54 +0800 Subject: [PATCH 201/361] Follow App Store submit rule, upgrade the min Xcode version to Xcode 9.0 Using `@available` and `API_AVAILABLE` to check API availability --- .../SDWebImage Demo/LaunchScreen.storyboard | 12 ++++++++---- README.md | 2 +- SDWebImage/SDImageCoderHelper.m | 13 ++++--------- SDWebImage/SDImageIOCoder.m | 19 +++---------------- SDWebImage/SDWebImageCompat.h | 4 ---- SDWebImage/SDWebImageTransition.h | 2 +- 6 files changed, 17 insertions(+), 35 deletions(-) diff --git a/Examples/SDWebImage Demo/LaunchScreen.storyboard b/Examples/SDWebImage Demo/LaunchScreen.storyboard index 66a76819..12baca9e 100644 --- a/Examples/SDWebImage Demo/LaunchScreen.storyboard +++ b/Examples/SDWebImage Demo/LaunchScreen.storyboard @@ -1,8 +1,12 @@ - + + + + - + + @@ -14,9 +18,9 @@ - + - + diff --git a/README.md b/README.md index 92858518..a1dc3ee2 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ This library provides an async image downloader with cache support. For convenie - tvOS 9.0 or later - watchOS 2.0 or later - macOS 10.10 or later -- Xcode 7.3 or later +- Xcode 9.0 or later #### Backwards compatibility diff --git a/SDWebImage/SDImageCoderHelper.m b/SDWebImage/SDImageCoderHelper.m index 6aff85df..a08abf68 100644 --- a/SDWebImage/SDImageCoderHelper.m +++ b/SDWebImage/SDImageCoderHelper.m @@ -203,20 +203,15 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over static CGColorSpaceRef colorSpace; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunguarded-availability" - BOOL shouldUseSRGB = NO; #if SD_UIKIT - NSProcessInfo *processInfo = [NSProcessInfo processInfo]; - shouldUseSRGB = processInfo.operatingSystemVersion.majorVersion >= 9; -#endif - if (shouldUseSRGB) { - // This is what iOS/tvOS device used colorspace, combined with right bitmapInfo, even without decode, can still avoid extra CA::Render::copy_image(which marked `Color Copied Images` from Instruments) + if (@available(iOS 9.0, tvOS 9.0, *)) { colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); } else { colorSpace = CGColorSpaceCreateDeviceRGB(); } -#pragma clang diagnostic pop +#else + colorSpace = CGColorSpaceCreateDeviceRGB(); +#endif }); return colorSpace; } diff --git a/SDWebImage/SDImageIOCoder.m b/SDWebImage/SDImageIOCoder.m index 9542fbde..4701f095 100644 --- a/SDWebImage/SDImageIOCoder.m +++ b/SDWebImage/SDImageIOCoder.m @@ -240,28 +240,15 @@ static BOOL canDecode = NO; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunguarded-availability" #if TARGET_OS_SIMULATOR || SD_WATCH canDecode = NO; -#elif SD_MAC - NSProcessInfo *processInfo = [NSProcessInfo processInfo]; - if ([processInfo respondsToSelector:@selector(operatingSystemVersion)]) { - // macOS 10.13+ - canDecode = processInfo.operatingSystemVersion.minorVersion >= 13; - } else { - canDecode = NO; - } -#elif SD_UIKIT - NSProcessInfo *processInfo = [NSProcessInfo processInfo]; - if ([processInfo respondsToSelector:@selector(operatingSystemVersion)]) { - // iOS 11+ && tvOS 11+ - canDecode = processInfo.operatingSystemVersion.majorVersion >= 11; +#else + if (@available(iOS 11.0, tvOS 11.0, macOS 10.13, *)) { + canDecode = YES; } else { canDecode = NO; } #endif -#pragma clang diagnostic pop }); return canDecode; } diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index 6fd79b6b..f47a248a 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -63,10 +63,6 @@ #define UIColor NSColor #endif #else - #if __IPHONE_OS_VERSION_MIN_REQUIRED != 20000 && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0 - #error SDWebImage doesn't support Deployment Target version < 5.0 - #endif - #if SD_UIKIT #import #endif diff --git a/SDWebImage/SDWebImageTransition.h b/SDWebImage/SDWebImageTransition.h index fcf193f6..e841a962 100644 --- a/SDWebImage/SDWebImageTransition.h +++ b/SDWebImage/SDWebImageTransition.h @@ -41,7 +41,7 @@ typedef void (^SDWebImageTransitionCompletionBlock)(BOOL finished); /** The timing function used for all animations within this transition animation (macOS). */ -@property (nonatomic, strong, nullable) CAMediaTimingFunction *timingFunction NS_AVAILABLE_MAC(10_7); +@property (nonatomic, strong, nullable) CAMediaTimingFunction *timingFunction API_UNAVAILABLE(ios, tvos, watchos); /** A mask of options indicating how you want to perform the animations. */ From ab86065f38e5960a8dd4da136de9dd9af33883cf Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Sun, 8 Jul 2018 14:26:38 +0800 Subject: [PATCH 202/361] Fix image prefetcher completion logical handler --- SDWebImage/SDWebImagePrefetcher.m | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index c4490cea..035354eb 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -15,8 +15,9 @@ // These value are just used as incrementing counter, keep thread-safe using memory_order_relaxed for performance. atomic_ulong _skippedCount; atomic_ulong _finishedCount; - atomic_ulong _totalCount; atomic_flag _isAllFinished; + + unsigned long _totalCount; } @property (nonatomic, copy, readwrite) NSArray *urls; @@ -105,7 +106,7 @@ // Current operation finished [sself callProgressBlockForToken:token imageURL:imageURL]; - if (atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed) + atomic_load_explicit(&(token->_skippedCount), memory_order_relaxed) >= atomic_load_explicit(&(token->_totalCount), memory_order_relaxed)) { + if (atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed) == token->_totalCount) { // All finished if (!atomic_flag_test_and_set_explicit(&(token->_isAllFinished), memory_order_relaxed)) { [sself callCompletionBlockForToken:token]; @@ -138,7 +139,7 @@ NSUInteger tokenFinishedCount = [self tokenFinishedCount]; NSUInteger tokenTotalCount = [self tokenTotalCount]; NSUInteger finishedCount = atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed); - NSUInteger totalCount = atomic_load_explicit(&(token->_totalCount), memory_order_relaxed); + NSUInteger totalCount = token->_totalCount; dispatch_async(self.delegateQueue, ^{ if (shouldCallDelegate) { [self.delegate imagePrefetcher:self didPrefetchURL:url finishedCount:tokenFinishedCount totalCount:tokenTotalCount]; @@ -173,7 +174,7 @@ NSUInteger tokenTotalCount = 0; @synchronized (self.runningTokens) { for (SDWebImagePrefetchToken *token in self.runningTokens) { - tokenTotalCount += atomic_load_explicit(&(token->_totalCount), memory_order_relaxed); + tokenTotalCount += token->_totalCount; } } return tokenTotalCount; From 28eb1b4b5cad170c96c1bd8ec7a492a9edab2b73 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Mon, 9 Jul 2018 16:32:47 +0800 Subject: [PATCH 203/361] Fix crash when assign request property of SDWebImageDownloadToken --- SDWebImage/SDWebImageDownloader.h | 4 ++-- SDWebImage/SDWebImageDownloader.m | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index 4996f7c0..351d57d1 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -109,12 +109,12 @@ typedef SDImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock; /** The download's request. */ -@property (nonatomic, copy, nullable, readonly) NSURLRequest *request; +@property (nonatomic, strong, nullable, readonly) NSURLRequest *request; /** The download's response. */ -@property (nonatomic, copy, nullable, readonly) NSURLResponse *response; +@property (nonatomic, strong, nullable, readonly) NSURLResponse *response; @end diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index cc17dd89..8e0f89bb 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -19,8 +19,8 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; @interface SDWebImageDownloadToken () @property (nonatomic, strong, nullable, readwrite) NSURL *url; -@property (nonatomic, copy, nullable, readwrite) NSURLRequest *request; -@property (nonatomic, copy, nullable, readwrite) NSURLResponse *response; +@property (nonatomic, strong, nullable, readwrite) NSURLRequest *request; +@property (nonatomic, strong, nullable, readwrite) NSURLResponse *response; @property (nonatomic, strong, nullable, readwrite) id downloadOperationCancelToken; @property (nonatomic, weak, nullable) NSOperation *downloadOperation; @property (nonatomic, weak, nullable) SDWebImageDownloader *downloader; From 153af72369dca6411a4658e22bf5bdb531437746 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Wed, 11 Apr 2018 11:41:08 +0300 Subject: [PATCH 204/361] Set version to 5.0.0-beta, Xcode 8 required, updated the CHANGELOG and added 5.0 Migration Guide --- CHANGELOG.md | 50 +++++++ Docs/SDWebImage-5.0-Migration-guide.md | 173 +++++++++++++++++++++++++ README.md | 3 +- SDWebImage.podspec | 2 +- WebImage/Info.plist | 4 +- 5 files changed, 228 insertions(+), 4 deletions(-) create mode 100644 Docs/SDWebImage-5.0-Migration-guide.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ebf44af..762b2a8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,53 @@ +## [5.0.0 - Release_name_TBD, on Apr xxth, 2018](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta) +See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/milestone/15) + +#### Infrastructure +- the new requirements are **iOS 8.0+** and **macOS 10.10+** #2147 + +#### Backwards incompatible changes + +See the [5.0 Migration Guide](Docs/SDWebImage-5.0-Migration-guide.md) for a list of comprehensive changes and the way to update your code + +#### Features +- Introduce `SDAnimatedImageView`, `SDAnimatedImage` and refactor the way we handle animated images #2140 +- Added APNG support via dedicated coder `SDWebImageAPNGCoder` #2149 +- Refactored `SDWebImageDownloader` configs, separated them into a dedicated `SDWebImageDownloaderConfig` object #2263 +- Refactored the way we work with the scale factor #2266 +- Created request and response modifier #2261 +- Refactor Cache Path API #2276 +- Refactor custom cache serializer & headers filter for request level #2280 +- Refactor cache - Support custom memory cache & disk cache #2282 +- Refactor cache - Support custom web cache #2278 +- Refactor - custom image loader - Supports loader protocol #2256 +- Use `SDWebImageAvoidDecodeImage` to allow user to control force decode feature for individual image request #2283 + +- `SDImageCache` supports disk cache writing options. See `SDImageCacheConfig diskCacheWritingOptions` #2148 +- `SDImageCache` now uses `NSData writeToFile:options:error` instead of `NSFileManager createFileAtPath:contents:attributes` #2148 +- Moved `SDImageCache maxMemoryCost` and `SDImageCache maxMemoryCountLimit` to `SDImageCacheConfig` #2151 +- Added `SDImageCache diskImageDataExistsWithKey:` synchronous method #2151 +- Moved `UIImage sd_imageLoopCount` and `UIImage isGIF` (and renamed to `sd_isAnimated`) to `UIImage+WebCache` category, removed the outdated methods #2152 +- Move context and other type definitions to a separate header (`SDWebImageDefine`) to allow to be included without dependency #2188 +- Pass `context` arg from the top level APIs to the bottom level APIs to allow specify logic in the future #2189 d6a3e2c c24c3d3 +- Refactor the image indicator by creating `SDWebImageIndicator` and `SDWebImageProgressIndicator` protocols and two concrete classes that implement activity and progress indicators for both UIKit and AppKit #2185 46b62cf +- Refactor the implementation of `SDWebImagePrefetcher` so it behaves more like a "shared instance" object, similar to other platform classes. Each instance will manage its own list of urls. #2191 1efc247 92f3d2c bc164d6 +- Refactored and enhanced the way we allow image transformations. Switched from a single delegate method to composition of `SDWebImageTransformer` #2219 +- API style refactoring - #2250 + - Use property instead of setters and getters to make the property available in Swift + - Use class property with the correct name instead of `+(instanceType)sharedInstance` in singleton to make it more easy to use in Swift. The generated interface should be simple `open class var shared { get }` + - Add all nullability annotation to avoid any `AnyObject!` implicitly unwrapped optionals (Except that `null_resettable`) + - Add all Core Foundation Ownership using `CF_RETURNS_RETAINED` for + Get Rule and `CF_RETURNS_NOT_RETAINED` for Create Rule to avoid any `Unmanaged` CF value + - Change all key for Dictionary with `NS_STRING_ENUM` to make it easy to use in Swift with dot syntax + - Change all global value type which represent enum with `NS_TYPED_ENUM` to make it easy to use in Swift with dot syntax +- Remove the extra calculation of image orientation for ImageIO coder & Fix macOS image orientation #2271 +- Added `SDWebImageError` (defined as `NS_ERROR_ENUM`) to group all our errors together #2290 +- Added tests for macOS + +#### Fixes +- `SDWebImageManager loadImageWithURL:options:progress:completed:` changed the `completed` param requirement from `nullable` to `nonnull` #2164 + +TODO: Update diagrams + ## [4.4.1 - 4.4 patch, on June 7th, 2018](https://github.com/rs/SDWebImage/releases/tag/4.4.1) See [all tickets marked for the 4.4.1 release](https://github.com/rs/SDWebImage/milestone/26) diff --git a/Docs/SDWebImage-5.0-Migration-guide.md b/Docs/SDWebImage-5.0-Migration-guide.md new file mode 100644 index 00000000..3aaf0c65 --- /dev/null +++ b/Docs/SDWebImage-5.0-Migration-guide.md @@ -0,0 +1,173 @@ +## SDWebImage 5.0 Migration Guide + +SDWebImage 5.0 is the latest major release of SDWebImage, a top library for downloading and caching images. +As a major release, following [Semantic Versioning](http://semver.org/) conventions, 5.0 introduces several API-breaking changes with its new architecture. + +.... RELEASE_SUMMARY .... + +This guide is provided in order to ease the transition of existing applications using SDWebImage 4.X to the latest APIs, as well as explain the design and structure of new and changed functionality. + +### Requirements: iOS 8, Mac OS X 10.10, watchOS 2, tvOS 9, Xcode 8 + +SDWebImage 5.0 officially supports iOS 8 and later, Mac OS X 10.10 and later, watchOS 2 and later and tvOS 9 and later. +It needs Xcode 8 or later to be able to build everything properly. + +For targeting previous versions of the SDKs, check [README - Backwards compatibility](https://github.com/rs/SDWebImage#backwards-compatibility) +. + +### Migration + +#### Swift + +#### Objective-C + +example + +SDWebImage 4.x +``` +[imageView sd_setImageWithURL:url placeholderImage:placeholderImage]; +``` + +SDWebImage 5.x +``` +[imageView sd_setImageWithURL:url placeholderImage:placeholderImage]; +``` + +### Entities + +#### Added +... + +#### SDImageCache + +- new initializer `initWithNamespace:diskCacheDirectory:config:`, is now the designated initializer +- moved `maxMemoryCost` and `maxMemoryCountLimit` to `SDImageCacheConfig` +- added `SDImageCache diskImageDataExistsWithKey:` synchronous method +- `addReadOnlyCachePath:` removed, use `additionalCachePathBlock` instead +- `cachePathForKey:inPath:` removed, use `cachePathForKey:` with NSString's path API instead. +- `defaultCachePathForKey:` removed, use `cachePathForKey:` instead + +#### SDImageCacheConfig + +- added `diskCacheWritingOptions` of type `NSDataWritingOptions`, defaults to `NSDataWritingAtomic` +- added `maxMemoryCost` and `maxMemoryCountLimit` properties (used to be in `SDImageCache`) +- `shouldDecompressImages` removed. Use `SDImageCacheAvoidDecodeImage` in cache options instead + +#### SDWebImageManager + +- `loadImageWithURL:options:progress:completed:` changed the `completed` param requirement from `nullable` to `nonnull` +- `loadImageWithURL:options:progress:completed:` return type `id` changed to `SDWebImageCombinedOperation *` +- `shared()` changed to `shared` +- `isRunning()` changed to `isRunning` +- `imageCache` changed from nullable to nonnull +- `imageDownloader` renamed to `imageLoader` and changed from nullable to nonnull +- `cacheKeyFilter` property type changed to `id`, use the `SDWebImageCacheKeyFilter cacheKeyFilterWithBlock:` +- `cacheSerializer` property type CHANGED to `id`, use the `SDWebImageCacheSerializer cacheSerializerWithBlock:` +- `imageCache` property type changed from `SDImageCache *` to `id`. The default value does not change. +- `initWithCache:downloader:` 's `cache` arg type changed from `SDImageCache *` to `id` +- `initWithCache:downloader` renamed to `initWithCache:loader:` +- `saveImageToCache:forURL:` removed. Use `SDImageCache storeImage:imageData:forKey:cacheType:completion:` (or `SDImageCache storeImage:forKey:toDisk:completion:` if you use default cache class) with `cacheKeyForURL:` instead. +- `diskImageExistsForURL:completion:` removed. Use `SDImageCache containsImageForKey:cacheType:completion:` (or `SDImageCache diskImageExistsWithKey:completion:` if you use default cache class) with `cacheKeyForURL:` instead. +- `cachedImageExistsForURL:completion` removed. Use `SDImageCache containsImageForKey:cacheType:completion:` (or `SDImageCache diskImageExistsWithKey:completion:` and `SDImageCache imageFromMemoryCacheForKey:` if you use default cache class) with `cacheKeyForURL:` instead. + +#### SDWebImageManagerDelegate + +- removed `imageManager:transformDownloadedImage:forKey:` + +#### UIView and subclasses (UIImageView, UIButton, ...) + +- `sd_internalSetImageWithURL:placeholderImage:options:operationKey:setImageBlock:progress:completed:` renamed to `UIView sd_internalSetImageWithURL:placeholderImage:options:context:setImageBlock:progress:completed:` (The biggest changes is that the completion block type from `SDExternalCompletionBlock` to `SDInternalCompletionBlock`. Which allow advanced user to get more information of image loading process) +- `sd_internalSetImageWithURL:placeholderImage:options:operationKey:setImageBlock:progress:completed:context:` removed +- activity indicator refactoring - use `sd_imageIndicator` with `SDWebImageActivityIndicator` + - `sd_setShowActivityIndicatorView:` removed + - `sd_setIndicatorStyle:` removed + - `sd_showActivityIndicatorView` removed + - `sd_addActivityIndicator:` removed + - `sd_removeActivityIndicator:` removed + +#### UIImage + +- Renamed `isGIF` to `sd_isAnimated`, also `NSImage isGIF` renamed to `NSImage sd_isAnimated` +- Renamed `decodedImageWithImage:` to `sd_decodedImageWithImage:` +- Renamed `decodedAndScaledDownImageWithImage:` to `sd_decodedAndScaledDownImageWithImage:` +- Removed `sd_webpLoopCount` since we have `sd_imageLoopCount` + +#### UIImageView + +- Removed `sd_setImageWithPreviousCachedImageWithURL:placeholderImage:options:progress:completed` + +#### SDWebImageDownloader + +- `shared()` changed to `shared` +- `setOperationClass` available for Swift user +- `setSuspended(_:)` changed to `isSuspended` property +- `shouldDecompressImages` moved to `SDWebImageDownloaderConfig.shouldDecompressImages` +- `maxConcurrentDownloads` moved to `SDWebImageDownloaderConfig.maxConcurrentDownloads` +- `downloadTimeout` moved to `SDWebImageDownloaderConfig.downloadTimeout` +- `operationClass` moved to `SDWebImageDownloaderConfig.operationClass` +- `executionOrder` moved to `SDWebImageDownloaderConfig.executionOrder` +- `urlCredential` moved to `SDWebImageDownloaderConfig.urlCredential` +- `username` moved to `SDWebImageDownloaderConfig.username` +- `password` moved to `SDWebImageDownloaderConfig.password` +- `initWithSessionConfiguration:` removed, use `initWithConfig:]` with session configuration instead +- `createNewSessionWithConfiguration:` removed, use `initWithConfig:]` with new session configuration instead. To modify shared downloader configuration, provide custom `SDWebImageDownloaderConfig.defaultDownloaderConfig` before it created. +- `headersFilter` removed, use `requestModifier` instead +- `cancel:` removed, use `SDWebImageDownloadToken cancel` instead +- `shouldDecompressImages` removed. Use `SDWebImageDownloaderAvoidDecodeImage` in downloader options instead + +#### SDWebImageDownloaderOperation + +- `initWithRequest:inSession:options:context:` is now the designated initializer +- Removed `shouldUseCredentialStorage` property +- `SDWebImageDownloadOperationInterface` protocol renamed to `SDWebImageDownloadOperation`. (`SDWebImageDownloadOperationProtocol` for Swift) +- `expectedSize` removed, use `response.expectedContentLength` instead +- `shouldDecompressImages` removed. Use `SDWebImageDownloaderAvoidDecodeImage` in downloader options instead. + +#### SDWebImagePrefetcher + +- `prefetchURLs:` and `prefetchURLs:progress:completed:` return types changed from `void` to `SDWebImagePrefetchToken` +- `prefetcherQueue` property renamed to `delegateQueue` +- `maxConcurrentDownloads` property removed, use `SDWebImageManager.downloader` config instead + +#### SDWebImageCoder +- `SDCGColorSpaceGetDeviceRGB()` moved to `SDWebImageCoderHelper colorSpaceGetDeviceRGB` +- `SDCGImageRefContainsAlpha()`, moved to `SDWebImageCoderHelper imageRefContainsAlpha:` +- `decodedImageWithData:` replaced with `decodedImageWithData:options:` +- `encodedDataWithImage:format:` replaced with `encodedDataWithImage:format:options` +- `init` method from `SDWebImageProgressiveCoder` changed to `initIncrementalWithOptions:` +- `incrementalDecodedImageWithData:finished` replaced with `updateIncrementalData:finished` and `incrementalDecodedImageWithOptions:` +- removed `decompressedImage:data:options` + +#### SDWebImageCodersManager + +- `sharedInstance()` changed to `shared` + +#### SDWebImageImageIOCoder + +- `shared()` changed to `shared` + +#### SDWebImageGIFCoder + +- `shared()` changed to `shared` + +#### SDWebImageWebPCoder + +- `shared()` changed to `shared` + +#### NSData-ImageContentType + +- `sd_UTTypeFromSDImageFormat` return `CFString` instead of `Unmanaged` + +#### UIButton-WebCache + +- `sd_currentImageURL()` changed to `sd_currentImageURL` + +#### NSButton-WebCache + +- `sd_currentImageURL()` changed to `sd_currentImageURL` +- `sd_currentAlternateImageURL()` changed to `sd_currentAlternateImageURL` + +#### Constants + +- `SDWebImageInternalSetImageGroupKey` renamed to `SDWebImageContextSetImageGroup` +- `SDWebImageExternalCustomManagerKey` renamed to `SDWebImageContextCustomManager` diff --git a/README.md b/README.md index a1dc3ee2..8721d44b 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ This library provides an async image downloader with cache support. For convenie #### Backwards compatibility -- For iOS 7 and macOS 10.9, use [any 4.x version up to 4.3.3](https://github.com/rs/SDWebImage/releases/tag/4.3.3) +- For iOS 7, macOS 10.9 or Xcode < 8, use [any 4.x version up to 4.3.3](https://github.com/rs/SDWebImage/releases/tag/4.3.3) - For macOS 10.8, use [any 4.x version up to 4.3.0](https://github.com/rs/SDWebImage/releases/tag/4.3.0) - For iOS 5 and 6, use [any 3.x version up to 3.7.6](https://github.com/rs/SDWebImage/tag/3.7.6) - For iOS < 5.0, please use the last [2.0 version](https://github.com/rs/SDWebImage/tree/2.0-compat). @@ -53,6 +53,7 @@ This library provides an async image downloader with cache support. For convenie - Read the [Documentation @ CocoaDocs](http://cocoadocs.org/docsets/SDWebImage/) - Try the example by downloading the project from Github or even easier using CocoaPods try `pod try SDWebImage` - Read the [Installation Guide](https://github.com/rs/SDWebImage/wiki/Installation-Guide) +- Read the [SDWebImage 5.0 Migration Guide](Docs/SDWebImage-5.0-Migration-guide.md) to get an idea of the changes from 4.x to 5.x - Read the [SDWebImage 4.0 Migration Guide](Docs/SDWebImage-4.0-Migration-guide.md) to get an idea of the changes from 3.x to 4.x - Read the [Common Problems](https://github.com/rs/SDWebImage/wiki/Common-Problems) to find the solution for common problems - Go to the [Wiki Page](https://github.com/rs/SDWebImage/wiki) for more information such as [Advanced Usage](https://github.com/rs/SDWebImage/wiki/Advanced-Usage) diff --git a/SDWebImage.podspec b/SDWebImage.podspec index f78dbe94..84ef3a63 100644 --- a/SDWebImage.podspec +++ b/SDWebImage.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'SDWebImage' - s.version = '4.4.1' + s.version = '5.0.0-beta' s.osx.deployment_target = '10.10' s.ios.deployment_target = '8.0' diff --git a/WebImage/Info.plist b/WebImage/Info.plist index 81e2ffa0..77696b33 100644 --- a/WebImage/Info.plist +++ b/WebImage/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 4.4.1 + 5.0.0-beta CFBundleSignature ???? CFBundleVersion - 4.4.1 + 5.0.0-beta NSPrincipalClass From 99b96e4be14a1b7b5e364a20259df8ed1cca5f7c Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Thu, 12 Jul 2018 12:35:12 +0300 Subject: [PATCH 205/361] Updates --- CHANGELOG.md | 8 +++-- Docs/SDWebImage-5.0-Migration-guide.md | 41 +++++++++++--------------- Docs/SDWebImage.mdj | 4 +-- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 762b2a8b..365f4c13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/ #### Infrastructure - the new requirements are **iOS 8.0+** and **macOS 10.10+** #2147 +- **Xcode 9+** #### Backwards incompatible changes @@ -10,7 +11,7 @@ See the [5.0 Migration Guide](Docs/SDWebImage-5.0-Migration-guide.md) for a list #### Features - Introduce `SDAnimatedImageView`, `SDAnimatedImage` and refactor the way we handle animated images #2140 -- Added APNG support via dedicated coder `SDWebImageAPNGCoder` #2149 +- Added APNG support via dedicated coder `SDImageAPNGCoder` #2149 - Refactored `SDWebImageDownloader` configs, separated them into a dedicated `SDWebImageDownloaderConfig` object #2263 - Refactored the way we work with the scale factor #2266 - Created request and response modifier #2261 @@ -30,7 +31,7 @@ See the [5.0 Migration Guide](Docs/SDWebImage-5.0-Migration-guide.md) for a list - Pass `context` arg from the top level APIs to the bottom level APIs to allow specify logic in the future #2189 d6a3e2c c24c3d3 - Refactor the image indicator by creating `SDWebImageIndicator` and `SDWebImageProgressIndicator` protocols and two concrete classes that implement activity and progress indicators for both UIKit and AppKit #2185 46b62cf - Refactor the implementation of `SDWebImagePrefetcher` so it behaves more like a "shared instance" object, similar to other platform classes. Each instance will manage its own list of urls. #2191 1efc247 92f3d2c bc164d6 -- Refactored and enhanced the way we allow image transformations. Switched from a single delegate method to composition of `SDWebImageTransformer` #2219 +- Refactored and enhanced the way we allow image transformations. Switched from a single delegate method to composition of `SDImageTransformer` #2219 - API style refactoring - #2250 - Use property instead of setters and getters to make the property available in Swift - Use class property with the correct name instead of `+(instanceType)sharedInstance` in singleton to make it more easy to use in Swift. The generated interface should be simple `open class var shared { get }` @@ -42,6 +43,9 @@ See the [5.0 Migration Guide](Docs/SDWebImage-5.0-Migration-guide.md) for a list - Remove the extra calculation of image orientation for ImageIO coder & Fix macOS image orientation #2271 - Added `SDWebImageError` (defined as `NS_ERROR_ENUM`) to group all our errors together #2290 - Added tests for macOS +- Add the `SDWebImageContextStoreCacheType` context option to specify target cache type when the image is downloaded by manager and will store to cache #2360 +- Feature watchOS `WKInterfaceImage` with `sd_setImageWithURL` #2331 +- Add options to specify query cache sync/async behavior #2312 #### Fixes - `SDWebImageManager loadImageWithURL:options:progress:completed:` changed the `completed` param requirement from `nullable` to `nonnull` #2164 diff --git a/Docs/SDWebImage-5.0-Migration-guide.md b/Docs/SDWebImage-5.0-Migration-guide.md index 3aaf0c65..936e42e2 100644 --- a/Docs/SDWebImage-5.0-Migration-guide.md +++ b/Docs/SDWebImage-5.0-Migration-guide.md @@ -3,14 +3,12 @@ SDWebImage 5.0 is the latest major release of SDWebImage, a top library for downloading and caching images. As a major release, following [Semantic Versioning](http://semver.org/) conventions, 5.0 introduces several API-breaking changes with its new architecture. -.... RELEASE_SUMMARY .... - This guide is provided in order to ease the transition of existing applications using SDWebImage 4.X to the latest APIs, as well as explain the design and structure of new and changed functionality. -### Requirements: iOS 8, Mac OS X 10.10, watchOS 2, tvOS 9, Xcode 8 +### Requirements: iOS 8, Mac OS X 10.10, watchOS 2, tvOS 9, Xcode 9 SDWebImage 5.0 officially supports iOS 8 and later, Mac OS X 10.10 and later, watchOS 2 and later and tvOS 9 and later. -It needs Xcode 8 or later to be able to build everything properly. +It needs Xcode 9 or later to be able to build everything properly. For targeting previous versions of the SDKs, check [README - Backwards compatibility](https://github.com/rs/SDWebImage#backwards-compatibility) . @@ -19,25 +17,18 @@ For targeting previous versions of the SDKs, check [README - Backwards compatibi #### Swift +- TBD if needed - + #### Objective-C -example +- TBD if needed - -SDWebImage 4.x -``` -[imageView sd_setImageWithURL:url placeholderImage:placeholderImage]; -``` - -SDWebImage 5.x -``` -[imageView sd_setImageWithURL:url placeholderImage:placeholderImage]; -``` +### FLAnimatedImage support moved to a dedicated plugin repo +We are no longer hosting the integration with `FLAnimatedImage` inside this repo. We have a dedicated repo for that. +TBD ### Entities -#### Added -... - #### SDImageCache - new initializer `initWithNamespace:diskCacheDirectory:config:`, is now the designated initializer @@ -114,6 +105,8 @@ SDWebImage 5.x - `headersFilter` removed, use `requestModifier` instead - `cancel:` removed, use `SDWebImageDownloadToken cancel` instead - `shouldDecompressImages` removed. Use `SDWebImageDownloaderAvoidDecodeImage` in downloader options instead +- use `SDWebImageLoaderProgressBlock` instead of `SDWebImageDownloaderProgressBlock` +- use `SDWebImageLoaderCompletedBlock` instead of `SDWebImageDownloaderCompletedBlock` #### SDWebImageDownloaderOperation @@ -129,28 +122,28 @@ SDWebImage 5.x - `prefetcherQueue` property renamed to `delegateQueue` - `maxConcurrentDownloads` property removed, use `SDWebImageManager.downloader` config instead -#### SDWebImageCoder -- `SDCGColorSpaceGetDeviceRGB()` moved to `SDWebImageCoderHelper colorSpaceGetDeviceRGB` -- `SDCGImageRefContainsAlpha()`, moved to `SDWebImageCoderHelper imageRefContainsAlpha:` +#### SDImageCoder +- `SDCGColorSpaceGetDeviceRGB()` moved to `SDImageCoderHelper colorSpaceGetDeviceRGB` +- `SDCGImageRefContainsAlpha()`, moved to `SDImageCoderHelper imageRefContainsAlpha:` - `decodedImageWithData:` replaced with `decodedImageWithData:options:` - `encodedDataWithImage:format:` replaced with `encodedDataWithImage:format:options` - `init` method from `SDWebImageProgressiveCoder` changed to `initIncrementalWithOptions:` - `incrementalDecodedImageWithData:finished` replaced with `updateIncrementalData:finished` and `incrementalDecodedImageWithOptions:` - removed `decompressedImage:data:options` -#### SDWebImageCodersManager +#### SDImageCodersManager - `sharedInstance()` changed to `shared` -#### SDWebImageImageIOCoder +#### SDImageIOCoder - `shared()` changed to `shared` -#### SDWebImageGIFCoder +#### SDImageGIFCoder - `shared()` changed to `shared` -#### SDWebImageWebPCoder +#### SDImageWebPCoder - `shared()` changed to `shared` diff --git a/Docs/SDWebImage.mdj b/Docs/SDWebImage.mdj index 9f5f7db3..dfbccdcf 100644 --- a/Docs/SDWebImage.mdj +++ b/Docs/SDWebImage.mdj @@ -20261,7 +20261,7 @@ "_parent": { "$ref": "AAAAAAFUkhyNUo23oFw=" }, - "name": "SDWebImageProgressiveDownload", + "name": "SDWebImageProgressiveLoad", "visibility": "public" }, { @@ -22759,4 +22759,4 @@ "visibility": "public" } ] -} \ No newline at end of file +} From bc44c5e438c53d38c79f11023c32b9cb9f6e3360 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Thu, 12 Jul 2018 20:54:03 +0300 Subject: [PATCH 206/361] Reviewed version of the migration guide - with @dreampiggy + added the API-Diff generated by @dreampiggy using objc-diff --- Docs/API-Diff/5.0/apidiff.css | 103 ++ Docs/API-Diff/5.0/apidiff.html | 1222 ++++++++++++++++++++++++ Docs/SDWebImage-5.0-Migration-guide.md | 133 ++- 3 files changed, 1415 insertions(+), 43 deletions(-) create mode 100644 Docs/API-Diff/5.0/apidiff.css create mode 100644 Docs/API-Diff/5.0/apidiff.html diff --git a/Docs/API-Diff/5.0/apidiff.css b/Docs/API-Diff/5.0/apidiff.css new file mode 100644 index 00000000..06231d30 --- /dev/null +++ b/Docs/API-Diff/5.0/apidiff.css @@ -0,0 +1,103 @@ +body { + font: 12px 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; + margin: 0; + padding: 0 2em 2em 2em; +} + +h1 { + margin-top: 30px; + margin-bottom: 30px; + font-size: 28px; + font-weight: bold; +} + +.headerFile { + margin-left: 20px; +} + +.headerName { + margin: 15px 0px 10px -20px; + padding: 4px 4px 4px 20px; + font-weight: bold; + font-size: 120%; + background-color: #f8f8f8; +} + +.differenceGroup { + margin-top: 5px; +} + +.difference { + padding-left: 20px; + font-family: Courier, Consolas, monospace; + font-size: 110%; +} + +.status { + font-style: italic; + font-size: 80%; +} + +.removed { + color: red; +} + +.added { + color: blue; +} + +.modified { + color: #080; +} + +.declaration { + font-family: Courier, Consolas, monospace; +} + +table { + border: 1px #888 solid; + padding: 2px; + border-spacing: 0px; + border-collapse: collapse; + margin-left: 40px; + margin-top: 7px; +} + +td, th { + font-size: 10px; + border: 1px #888 solid; + padding:3px 6px; +} + +th { + font-size: 10px; + text-align: center; + background-color: #eee; +} + +td { + font-size: 90%; + text-align: left; +} + +ul { + list-style: disc outside; + margin: 0 0 0 16px; + padding: 0; +} + +li { + margin-top: 7px; +} + +.message { + margin-left: 20px; + font-style: italic; + color: #888; +} + +a:link { color: #18396E; text-decoration: none; } +a:active { color: #18396E; text-decoration: none; } +a:visited { color: #003366; text-decoration: none; } +a:link:hover { color: #18396E; text-decoration: underline; } +a:visited:hover { color: #003366; text-decoration: underline; } diff --git a/Docs/API-Diff/5.0/apidiff.html b/Docs/API-Diff/5.0/apidiff.html new file mode 100644 index 00000000..02d5349f --- /dev/null +++ b/Docs/API-Diff/5.0/apidiff.html @@ -0,0 +1,1222 @@ + + + + + + + +